Renderers, a small community project

199 views
Skip to first unread message

Bertrand Meyer

unread,
Aug 3, 2018, 8:52:52 AM8/3/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch

I often find myself wanting to print out (usually for debugging purposes) a structure such as a hash table, i.e. writing `print (city_table)’ and getting a reasonable default view such as list of [value, key] pairs:

 

                [“PARIS”, ‘P’] [“CHICAGO”, ‘C’] [“RIGA”, ‘R’] …

 

print (x) actually displays x.out where `out’ is a STRING-returning function from class ANY which  by default yields an internal format but may be redefined in any class. Such redefinitions exist for basic types INTEGER etc., but no one has ever taken the trouble to write some for for EiffelBase data structure classes. (I am not a Gobo user but a quick look also did not reveal such redefinitions – maybe there is something else that I missed.) What I would find useful is to the kind of above simple representation, directly adapted to the semantics of each kind of data structure as understood by their users. If I have a hash table this is how I would like to see it in the debugger, not the internal representation. (Admittedly, EiffelStudio gurus tell me they don’t care, and can read that representation.) There is a class DEBUG_OUTPUT but its idea has not been exploited much either so far.

 

Building such a readable representation for the major data structures in EiffelBase does not seem to be a very large effort. We are talking about maybe a dozen cases. If anyone is willing to help I’d be happy to coordinate the effort. (Let me use this opportunity to apologize for not pushing more yet on the LLVM/WebAssembly idea discussed some time ago. It is a much more ambitious project and not enough people were willing to commit the necessary resources, which is understandable. This one is much smaller.)

 

Messing up right away with ANY or a core library class such as DEBUG_OUTPUT is not a good idea so as a first step I would propose a visitor-style approach, talking “about” structures from the outside rather than working inside of them. In other words, a solution such as

 

                {RENDERER}.output (my_structure)

 

yielding a STRING representing my_structure if RENDERER knows about its type, otherwise defaulting to my_structure.out. In other words, output in RENDERER (ms) would be written as something like

 

                if {ARRAY [ANY]] ms as a then

... nice representation of array `a’...

                elseif {HASH_TABLE [ANY, COMPARABLE] ms as h the

... nice representation of hash table h

                ...

                else ms.out end

 

(This is a first cut, there may be a more clever way.) Of course this scheme does not look like the ideal OO structure but it is what you have to write if you want an outside, visitor-style mechanism that applies to various types. It  has the dual advantage of allowing several renderers (inheriting from a general RENDERER class providing defaults). Once we are happy with one of them, we can always lobby for inclusion of the best solutions as redefinitions of `out’ in EiffelBase classes, restoring a textbook OO approach.

 

In my opinion the representations, as with the hash table representation above, should  be terse and as much as possible use symbols rather than words, to avoid having to worry about translation into various human languages.

 

I think having such code would be useful. This is not a major endeavor but it will proceed faster if a few people help. This would mean taking up a couple of example structures, telling me about it, and within a month or so (let’s say August 31) sending me the corresponding branches of the above conditional, with examples and test results. I am happy to do HASH_TABLE and provide it as a guideline for others.

 

Thanks,

 

-- BM

 

 

 

 

 

 

 

 

Larry Rix

unread,
Aug 3, 2018, 9:01:54 AM8/3/18
to Eiffel Users
Betrand,

If you make an example as a "guide", I can write the remainders.

Question: Is it best to do these as descendant classes with additional features and then have the Eiffel Software team extract the code back to the Base library classes -OR- ought it be applied directly to the Base classes through SVN or GitHub and then issue a pull request?

Because these will be on the Base libraries, perhaps someone can double-check me to ensure I have it right.


Kind Regards,

Larry

Bertrand Meyer

unread,
Aug 3, 2018, 9:04:31 AM8/3/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch

That answer was fast. I will write the HASH_TABLE version tomorrow.

 

-- BM

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
Visit this group at https://groups.google.com/group/eiffel-users.
For more options, visit https://groups.google.com/d/optout.

williams Lima

unread,
Aug 17, 2018, 5:00:21 PM8/17/18
to Eiffel Users
What is the status of this project? It looks like the perfect project for a starter like me.

regards
Williams

Larry Rix

unread,
Aug 17, 2018, 6:48:49 PM8/17/18
to Eiffel Users
Williams,

I have been toying with it myself and it turns out (like many things) to be a little more complex once one starts designing.

The issue has to do with the [G] data in HASH_TABLE [G, K]. One wants to know if the G represents a single column of data or many. Using the Base library, one can envision many possibilities for multi-column data. For example: Consider things in Base which might have columns of data?

READABLE_INDEXABLE Things

Things that can be iterated over for "columns" of data I think are READABLE_INDEXABLE things. For example: ARRAY [ARRAY [STRING]] might be a good start. Perhaps even HASH_TABLE [ARRAY [STRING], INTEGER], where the Key is a hash of the STRING.

Below is an illustration of the class descendants of READABLE_INDEXABLE, which covers a lot of ground for objects that might represent items in columns.

readable_indexable_descendants.PNG


  • A. HASH_TABLE & STRING_TABLE
    • Yep—a HASH_TABLE [G, K] can have a G that is also another HASH_TABLE and so on (n-dimensional)
    • The "columns" in a STRING_TABLE are the characters of the string. How do we display them? What is a sensible and common presentation?
  • B. ARRAY, ARRAYED_LIST, ARRAYED_STACK, LINKED_LIST, INTEGER_INTERVAL, STRING_32, and STRING_8
    • When it comes to arrays, we have a similar situation like HASH_TABLE where we can have n-dimensional presentations. What do we do? How do we keep the brakes on and not get silly, but cover straight forward things like strings, integers, and so on?
    • What if we have a very large INTEGER_INTERVAL? How many columns do we allow before we call it quits? How does one present the situation where the integer interval has exceeded the presentation limits?
  • C. STRING_32 / STRING_8 (see B. above)
  • D. TUPLE
    • The TUPLE presents a whole new challenge because the item Types in a TUPLE can be varied and complex. Do we limit our presentation of cell items to just a few basic types (strings, integers, bools, characters, etc)?
    • If we have non-presentation-covered Types, do we have a "place-holder"? What is that place holder? How is it presented?
Going Further

It is true that the presented need was for a presentation that looked something like plain old CSV, which handles row-column (2-dim arrays) just fine. However, there is JSON, YAML, HTML, and others, which are all quite capable of presenting n-dimensional data easily. Do we start with CSV 2-dim arrays only with just a few basic data types and some outlier place holders to start? Do we then add in JSON and HTML <table> structures for n-dim'd arrays of things?

Lots of questions, ideas, and perhaps even needs. I think the discussion first needs to develop a Design Document which says clearly what we want in a first-pass and what we are willing to ignore (boundaries and limits) so we don't go spinning off into endless design space.


On that note, I have not heard back from Bertrand. I presume he is busy up to his eyeballs in his normal day-to-day business and teaching matters. :-)



Larry Rix

unread,
Aug 17, 2018, 6:51:55 PM8/17/18
to Eiffel Users
One other complexity to note is the issue of order. I am presuming that the rows in a collection of things are in natural order unless they are in a container which is somehow hashed or the list has a comparator for establishing order. I think that is a bridge too far to worry about order and put the burden on the list-maker/care-taker to ensure the natural order of the list is the order they want the "out" to output.

williams Lima

unread,
Aug 17, 2018, 8:12:26 PM8/17/18
to Eiffel Users
Yes, nothing is so simple.
By the way, for me, it would be easier to think about those issues if I could see some use cases.
That way I could get a better understanding of the problem. Maybe it is better to construct
some examples of what we want to accomplish. A couple of powerpoint slides would suffice.

If you want to do some work on it we can communicate directly by email in order
to not pollute the forum. And of course make some updates here when convenient.

regards
Williams

Larry Rix

unread,
Aug 18, 2018, 1:01:01 PM8/18/18
to eiffel...@googlegroups.com
Here's a suggested use case
 
Iterate over any readable indexable list which contains items of type readable indexable as columns for each row. Output only column items which conform to the basic types such as string integer real or Boolean. Ignore types other than the basic types, presenting them as non applicable. Presume the list order is natural and the output routine has no responsibility for ordering the list prior to outputting it.

--

williams Lima

unread,
Aug 18, 2018, 1:51:14 PM8/18/18
to Eiffel Users
I got it.
I'll start working on it. 

regards
Williams

williams Lima

unread,
Aug 19, 2018, 11:40:08 AM8/19/18
to Eiffel Users
This is how I'm working on it. 
The idea is to have a model/view pattern.

regards
Williams
renderers.zip

Bertrand Meyer

unread,
Aug 19, 2018, 12:05:10 PM8/19/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch

Looks good (sorry, I got sidetracked) but please observe Eiffel style rules: meaningful feature names (column_count, not ncols), spaces before opening parentheses, “description” note at head of class, and never even think of writing a feature without a header comment (which, for a routine, must list every argument, e.g. – Print `n’ according to `format’).

 

-- BM

 

From: eiffel...@googlegroups.com [mailto:eiffel...@googlegroups.com] On Behalf Of williams Lima


Sent: Sunday, 19 August, 2018 18:40
To: Eiffel Users <eiffel...@googlegroups.com>

williams Lima

unread,
Aug 19, 2018, 12:10:59 PM8/19/18
to Eiffel Users
Of course Prof. Bertrand Meyer. I will pay more attention to style rules.

Thanks
Williams

Bertrand Meyer

unread,
Aug 19, 2018, 12:46:17 PM8/19/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch

Great, sorry for being fussy, but you write you are a beginner and not everyone realizes right away that style rules are an integral part of the Eiffel approach. Note that to change feature names you can use the refactoring tool (Context menu on feature -> Refactor -> Rename) – this will update the calls as well.

Ian Joyner

unread,
Aug 19, 2018, 7:18:04 PM8/19/18
to Eiffel Users
And that is the nice thing about Eiffel – the style is implied. You do not need the team of programmers needing to produce a huge style manual at the beginning (lots of which will be wrong, like using camelCase, ugh, or putting space inside parentheses( like this )).

I think I’d still like to see a syntax-free language to avoid all these problems and that each programmer could get an editor to display in the way that they like. But maybe you still need naming rules.

Perhaps syntax-free can be next iteration of Eiffel?

Ian

williams Lima

unread,
Aug 19, 2018, 7:44:48 PM8/19/18
to Eiffel Users
Dear friends

I had another idea on how to solve this problem. Of course it doesn't mean that 
I abandoned the first design attempt. The point is that this new idea looked so simple that I couldn't
resist trying to implement it.

I call it a flat renderer. The nice thing is that it can handle data of any dimension.
The idea is to print the data in a X Y Z ... format. The dots mean that the sequence can have an arbitrary
number of terms. In this format each column represents one dimension of the data and each datum is printed
in a different line. This output can later be analyzed and many different visualizations can be obtained from it.

The algorithm is basically a depth-first tree traversal with some minor adaptations.

I will prepare a better description of the design and improve the style of the source code. I just finished the initial coding 
with a working example and I'm quite excited to get your opinions about it.

regards
Williams
flat_renderer.zip

williams Lima

unread,
Aug 20, 2018, 5:20:55 PM8/20/18
to Eiffel Users
I added another test for the flat_renderer.
Now it is a 3D data structure. It is working like a charm.


regards
Williams

On Friday, August 3, 2018 at 9:52:52 AM UTC-3, Bertrand Meyer wrote:
flat_renderer_0.1.zip

williams Lima

unread,
Aug 20, 2018, 9:52:31 PM8/20/18
to Eiffel Users
In this version:
 - Improved documentation
 - Added tests for more basic types. Now
   STRING, INTEGER, REAL, and DOUBLE are supported
 - Added new test for three-dimensional data structure containing doubles

next steps:
 among other things, testing other data structures than ARRAYs

regards
Williams
flat_renderer-0.2.zip

javier hector

unread,
Aug 21, 2018, 8:32:43 AM8/21/18
to Eiffel Users
Hi Williams,

I would like to suggest to create a project on Github, so them we can collaborate and review the code.
Different strategies could be shared in branches until we have a good solution.

/Javier

williams Lima

unread,
Aug 21, 2018, 8:38:18 AM8/21/18
to eiffel...@googlegroups.com
Thanks Javier. I will do it now.

regards
Williams

williams Lima

unread,
Aug 21, 2018, 8:57:04 AM8/21/18
to Eiffel Users
I created a github project for the class FLAT_RENDERER.
the link is

I'm constantly doing additions to the files there and
will only post news about it here when
there are significant new improvements.

thanks
Williams

williams Lima

unread,
Aug 21, 2018, 5:06:56 PM8/21/18
to Eiffel Users
Jonathan Ostroff made a request to add one test for ARRAY2[STRING]
It is done and the changes are already available in the github project's repository:

The test result shows that the FLAT_RENDERER algorithm is 
working correctly but I need to say a few words about this particular
test using ARRAY2.

ARRAY2 is not a nested data structure. it is not n-dimensional and
this is the definition of multidimensional that I'm using in this implementation:
Def. (Dimension of a data structure) The dimension of a data structure correspond to the number of
nested levels in it.
Examples:
    ARRAY[ARRAY[REAL]] is a two dimensional structure
    ARRAY2[REAL] is a one-dimensional data structure because
    ARRAY2 stores data internally using a single ARRAY data structure.

So, ARRAY2 is, in reality, a linear data structure.
If we look at the output of the test (see image attached) we will see the
algorithm just output the natural order in which ARRAY2 stores its elements (row major order).

That said, the code seems to be working just fine.

regards
Williams
fig06.png

Larry Rix

unread,
Aug 22, 2018, 11:02:22 AM8/22/18
to eiffel...@googlegroups.com
Williams,

I am working towards a generalized solution, but starting at the bottom of the inheritance tree with the last descendants like ARRAY [G] and ARRAY2 [G]. For example: I have created an ARRAY2_EXT [G] and the test of it looks like:



The ARRAY2_EXT class presently looks like (below).

First—note that the `make_with_rows' and `set_rows' features are for convenience. An instance of the class can be created with the existing `make' and `make_filled' and other features of ARRAY2 [G]. So, the features I have added are simply to make using ARRAY2_EXT [G] more convenient and readable.



The real "magic" and point of the class is the `out_csv' feature, which appears below. The is one convenience feature (`is_basic_type') that I use to determine if a basic call to `out' on each array "item" is okay or not. Otherwise, we simply iterate over the rows and then columns, building each CSV row of items as text outputs, placing a new-line character at the end of each row.



The idea here is to carrying this simple notion of CSV output of basic types forward to each READABLE_INDEXABLE [G] class descendant, implementing it for each one independently. As I code each independent descendant, I will be looking for common code that I can factor up to a higher ancestor of each ?_EXT [G] class. Using multiple inheritance, I can then begin consolidating common code and inheriting that code in the descendants.

Like you have done, I will place this ECF project into GitHub for everyone to access.


Kind Regards,

Larry Rix

Larry Rix

unread,
Aug 22, 2018, 11:20:24 AM8/22/18
to Eiffel Users
Note that I just created a common ancestor class that I am calling READABLE_INDEXABLE_EXT (with no Generic). So far, this class has two features:

  • A deferred `out_csv' query.
  • The fully implemented `is_basic_type' query.
There may be more that factors back, but so far that's it. Each descendant now fully implements `out_csv'.

NOTE: Based on the STRING Result from `out_csv', this Result can then be reformatted to various forms: JSON, HTML, YAML, and so on—providing a wide range of possible outputs.


Cheers,

Larry

Larry Rix

unread,
Aug 22, 2018, 11:34:07 AM8/22/18
to Eiffel Users
The GitHub library project can be found here.

williams Lima

unread,
Aug 22, 2018, 11:46:21 AM8/22/18
to Eiffel Users
That was why you were so quiet lately. :)

Looks interesting. I will check it out.

regards
Williams

Larry Rix

unread,
Aug 22, 2018, 1:33:39 PM8/22/18
to Eiffel Users
Williams,

The first pass is basically complete. I need (and intend) to do the following:

  • Finish the remaining bottom-end descendants of READABLE_INDEXABLE with:
    • Appropriate convenience creation procedures
    • Appropriate out_csv and out_csv_common procedures (this needs a little more thought on how best to implement)
  • Ensure everything is:
    • Properly commented
    • Proper implementation of naming conventions
    • Properly noted
    • Clean in terms of spacing/tabbing/indenting, etc
  • Add any future design notes or tasking notes for TBD items (i.e. "How do we ____?)
  • Ensure everything is tested including:
    • Positive tests (does this work as expected?)
    • Negative tests (stress tests—or—try-to-make-it-break, letting the breaking tests prove robustness)
That's all I have for the moment. I need to get along with other matters today! It's already 1:30 PM and my day is just about gone!


Kind Regards,

Larry


Larry Rix

unread,
Aug 22, 2018, 1:36:02 PM8/22/18
to Eiffel Users
The GitHub project is now completely up to date as of this writing.

Larry Rix

unread,
Aug 22, 2018, 1:42:42 PM8/22/18
to eiffel...@googlegroups.com
BTW: A quick thought reminded me to attempt to test with multiple ad-hoc type mixtures. It appears to be working:



Larry Rix

unread,
Aug 22, 2018, 1:47:59 PM8/22/18
to Eiffel Users
Went a step further and mixed up the types of the columns to ensure the code can properly manage ad-hoc types in columns of each row (i.e. row 1 not the same as row 2 in col-by-col data type).

Appears that all is working as planned. :-)

Alexander Kogtenkov

unread,
Aug 22, 2018, 2:15:40 PM8/22/18
to eiffel...@googlegroups.com
A small style point: the test output string might look better if coded verbatim:

   "[
      moe,100,01/01/2018
      curly,200,01/02/2018
      shemp,300,01/03/2018
   ]"

Regards,
Alexander Kogtenkov


Larry Rix <lar...@moonshotsoftware.com>:

Alexander Kogtenkov

unread,
Aug 22, 2018, 2:16:39 PM8/22/18
to eiffel...@googlegroups.com
Is the project open? I'm getting "Page not found" error.

Regards,
Alexander Kogtenkov

Larry Rix <lar...@moonshotsoftware.com>:

Larry Rix

unread,
Aug 22, 2018, 2:21:02 PM8/22/18
to eiffel...@googlegroups.com
That is really strange that it made it private.

I just made it public.

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

--

Larry Rix

unread,
Aug 22, 2018, 2:41:34 PM8/22/18
to Eiffel Users
Style matter is handled as well.

Please let me know if the GitHub project does not show up as public.

ALSO: If someone wants to be added as a collaborator, please let me know. I can add as people might want or need.

Larry Rix

unread,
Aug 22, 2018, 2:43:17 PM8/22/18
to Eiffel Users
Bertrand,

Please take a peek at the GitHub project found here and see if it is headed towards the outcome you had in mind. The implementation of `print' in all of the descendants is not yet handled, but a few are. I will implement the remainder here shortly.

I want to start getting feedback so I know if I am on the right track or not.

Larry Rix

unread,
Aug 22, 2018, 3:38:24 PM8/22/18
to Eiffel Users
I ended up not redefining `print', but consolidating everything to `out'. Hopefully, this handles print when called and a READABLE_INDEXABLE_EXT object is passed.

Larry Rix

unread,
Aug 22, 2018, 6:41:33 PM8/22/18
to Eiffel Users
The library on GitHub has been updated with more notes, comments, tests, helper, and convenience features.

Jonathan Ostroff

unread,
Aug 22, 2018, 10:14:44 PM8/22/18
to 'Alexander Kogtenkov' via Eiffel Users

On Aug 22, 2018, at 6:41 PM, Larry Rix <lar...@moonshotsoftware.com> wrote:
The library on GitHub has been updated with more notes, comments, tests, helper, and convenience features.

Thanks Larry. 

In the ECF file at the above GitHub:

<library name="framework" location="$GITHUB\framework\framework.ecf"/>
<library name="html" location="$GITHUB\html\html.ecf"/>
<library name="json_ext" location="$GitHub\json_ext\json_ext.ecf"/>
<library name="randomizer" location="$GITHUB\randomizer\randomizer.ecf"/>
<library name="test_extension" location="$GITHUB\test_extension\test_extension.ecf”/>

I see “framework” and “html” at https://github.com/ljr1981/, but not the others.

Jonathan

Larry Rix

unread,
Aug 23, 2018, 6:51:38 AM8/23/18
to eiffel...@googlegroups.com
Removed the following unneeded libraries from the ECF:

- framework
- html
- json_ext
- process-safe
- randomizer

The only thing you're missing is then:



Kind Regards,

Larry

Larry Rix

unread,
Aug 23, 2018, 8:42:31 AM8/23/18
to Eiffel Users
I noted in Bertrand's description that he wanted to see key:value pairs, so I modified the code to show keys for objects that have keys (e.g. hash tables).

Otherwise, for objects that do not have keys, but still have row and column data, I added code that shows the row and column number. Of course, this only makes sense for items with n = 1 and n = 2 dimensions.

Example:

HASH_TABLE:
#17 - 1:moe,2:curly,3:shemp
#28 - 1:bugs,2:daffy,3:porky

Where the # (hash symbol) denotes the key followed by a dash, which denotes the beginning of the value. If the value part has multiple items (like an ARRAY), then those items print their element number as "N:value" (e.g. "1:moe" or "2:curly").

ARRAY:
1:1:moe,2:curly,3:shemp
2:1:bugs,2:daffy,3:porky

The difference with the ARRAY (and other non-keyed objects) is that there is no "#" (hash) mark to denote a key. Only the "row number" is presented in the form of "N:".


Cheers,

Larry

Larry Rix

unread,
Aug 23, 2018, 8:49:57 AM8/23/18
to eiffel...@googlegroups.com
Here is an example where the key (i.e. #) is not an INTEGER, but a STRING — using the same value content.

#PEOPLE - 1:moe,2:curly,3:shemp
#ANIMATIONS - 1:bugs,2:daffy,3:porky

Now—I can see clearly that according to my keys, I have both PEOPLE and ANIMATIONS in my hash table, where PEOPLE are the Three Stooges and ANIMATIONS are Looney Tunes characters.

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

--

Bertrand Meyer

unread,
Aug 23, 2018, 8:56:12 AM8/23/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch

I am happy that this little suggestion of mine met with such energy – and happy too to let it proceed on its own, obviously much further than what I had in mind (a class or a few). Thanks!

 

--- BMWith best regards,

 

-- Bertrand Meyer

--

You received this message because you are subscribed to the Google Groups "Eiffel Users" group.

To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Larry Rix

unread,
Aug 23, 2018, 10:01:49 AM8/23/18
to eiffel...@googlegroups.com, me...@inf.ethz.ch
I did not follow the visitor pattern, but the core code operates much as a visitor would. Hopefully, by using the ?_EXT pattern and creating simple descendants, the pathway to "fold in " in the ancestors of each is straightforward. My next task is to output simple JSON or HTML. I am also considering YAML,  but the more mainstream is the former.

Kind Regards, 

Larry

Larry Rix

unread,
Aug 24, 2018, 9:50:33 AM8/24/18
to Eiffel Users
I took a run at doing output of well-formed JSON, but failed. The code is a terrible design/implementation and is extremely fragile. I would not use it for production work at all. I have left the code with warning notes and tests to show what works and describe what is known to break. The whole notion of JSON output needs to be thought through. I think this is where the notion of a visitor pattern may make better sense such that each form of data structure can be responsible for representing itself as well-formed JSON.

williams Lima

unread,
Aug 25, 2018, 7:11:14 AM8/25/18
to Eiffel Users
I believe that I finally achieved my best design.
The core computational code has only about 20 lines and it is quite general.

please take a look at 

any comments are welcome.

thanks
Williams

Larry Rix

unread,
Aug 25, 2018, 2:45:29 PM8/25/18
to eiffel...@googlegroups.com
Hi Williams,

You did an excellent job. I like yours far better than mine. It appears you've got the better angle. That said—there are some improvements to be made. I cloned the repo you created and have updated it with tests.




NOTES:
  • Query vs Command
    • Changed from a Command-based feature to a Query-based, where the output is not sent to "io", but to Result as a STRING. This allows the consumer of this feature to send the Result to `print'.
    • A consequence of changing from Command to Query is that the calls you make in APPLICATION to FLAT_RENDERER no longer work as-is. I commented them out because testing now relies on test classes and not on running the APPLICATION code as though it is a test.
  • Type Changes
    • From STRING to HASHABLE: I removed direct expectations of STRING keys and so on from the routine (above). 
    • Why? Because the keys might be something other than STRING (i.e. INTEGER, DATE, etc.). 
    • We expect that objects with keys might be keyed using various HASHABLE things, and not just strings.
  • Local Variables
    • I renamed a few of the local variables to tell a better story and to use the naming and style conventions that I have found work well over the years.
  • Other
    • A consequence of change
First test result looks like:



SUMMARY:

I like your solution much better in certain regards because it is so simple (literally a two routines)! It doesn't have to upset the existing Base library code at all and can be used as-is alongside existing code without breaking Client code that uses the `out' feature (which is where I was going).

williams Lima

unread,
Aug 25, 2018, 3:05:12 PM8/25/18
to Eiffel Users
I really liked your new corrections and additions. It made the code
much more elegant and functional.

I guess I can update the main branch with your changes. 

Very thanks Larry. I'm learning.

Williams

Alexander Kogtenkov

unread,
Aug 25, 2018, 3:33:26 PM8/25/18
to eiffel...@googlegroups.com
Some side comments about further improvements:

1. It's 2018, Unicode is a "de facto" standard. It looks natural to talk STRING_32 from the beginning (including tests).
2. If there is a real structure with megabytes of output, do we want to create a string object? Wouldn't it be better to write down data directly to a stream (file, socket, standard output, etc.)? In that case the procedure would use an agent of type PROCEDURE [STRING_32]. (And the callers still expecting a string as a result, would simply pass `agent s32.append`.)
3. READABLE_INDEXABLE is great, what about ITERABLE?
4. Is this going to be extended to generate production-ready JSON, XML, CSV, etc.? If so, the visitor pattern seems to be unavoidable.
5. Should it become extendible, so that everyone can plug a visitor for a new type?
6. This one is tricky: what if there are cycles of objects (e.g., an array contains a reference to itself)? I guess, the limitation needs to be documented (formally or informally).

Regards,
Alexander Kogtenkov


Larry Rix <lar...@moonshotsoftware.com>:

Larry Rix

unread,
Aug 25, 2018, 3:49:47 PM8/25/18
to eiffel...@googlegroups.com
Hi Alex!

  1. Unicode—I agree. We need to be Unicode friendly all the way.
  2. I changed from an io output to a STRING output, which I think facilitates output to a file-based repo rather than the command line or whatever.
  3. I will have to take a look at ITERABLE, but I thought READABLE_INDEXABLE had enough coverage for the most basic types.
  4. My plan is to find a way towards JSON, XML, CSV, HTML <table> and so on. I think you're correct that the visitor pattern may well be unavoidable.
  5. I agree that in iterations further down the road ought to have a way to roll-your-own visitor.
  6. As far as reference cycles—I like how the Eiffel Studio class tool does it using "..." to indicate an inheritance cycle. Perhaps we can do something like that?

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

Larry Rix

unread,
Aug 25, 2018, 3:50:40 PM8/25/18
to eiffel...@googlegroups.com
Hi Williams,

If you'll make me a collaborator on the main or on a branch, then I can check in. I don't have rights at the moment.


Kind Regards,

Larry

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

williams Lima

unread,
Aug 25, 2018, 9:55:06 PM8/25/18
to Eiffel Users
Of course Larry. I just sent a collaborator invitation.

The comments by Alexander were all very pertinent.

Let's see how far can we go with this prototype.

regards
Williams
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Larry Rix

unread,
Aug 26, 2018, 8:03:27 AM8/26/18
to eiffel...@googlegroups.com
I received and accepted the collaborator invitation. I created a branch.

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

williams Lima

unread,
Aug 26, 2018, 10:02:49 AM8/26/18
to Eiffel Users
Great!
One thing Larry I would like to have help, in particular, is in the documentation of the source. I tried
to follow your guidelines as in the video "Eiffel Documentation - An Orientation Strategy" but
I don't know if I'm getting it right.

very thanks
Williams

williams Lima

unread,
Aug 26, 2018, 10:26:42 AM8/26/18
to Eiffel Users
Larry, when I tried to compile the class FLAT_RENDERER after adding your modifications I found that
the IF cases for DECIMAL and ABSOLUTE are dependent on the inclusion of other libraries.
If it is the case I believe we cannot go any further with this solution because we cannot expect the user
to have included all the libraries having classes being tested.

Seems like there is a major flaw in this strategy. I'm not certain.
Williams

Larry Rix

unread,
Aug 26, 2018, 10:36:14 AM8/26/18
to Eiffel Users
I will help you as best I can.

NOTE: Please take a quick peek at the branch I created (flat_renderer_lrix). Specifically, take a look at the first three check-in's (series of changes checked in to the branch repo).

  1. First check-in—gets the repo code in from my computer to the remote GitHub repo.
  2. Second check-in—Created a "test target", which entailed adding the <target name="test" ...> section to the ECF XML. Also, required adding an <exclude ...> for the "test" folder from the primary target.
    • Added the <exclude> for the "test" folder because this was the source of the error where ES was complaining about EQA_TEST_SET and EQA_COMMONLY_USED_ASSERTIONS.
    • I also had to change the Void-safety setting to Transitional and set Concurrency to Thread to get it to compile (these are my usual settings anyhow).
    • I added the test_extension library, which is a normal thing I do. NOTE: You may have to create a $GITHUB environment variable to point to where your root GitHub projects are stored. I do this to make the projects portable and all of my GitHub projects are stored in the same folder.
    • The testing-safe library moves from the primary target to the test target. This is what the TEST_SET_BRIDGE helps with.
    • I then created a new <target name="test" ... > XML section at the bottom of the ECF, which has all of the required configuration for the test target.
  3. Third check-in—Changing the configuration file to make a library target out of the primary target. This also removes the need for an APPLICATION class. The "tests" contained in it will be moved to one or more ?_TEST_SET class(es) to facilitate testing.
    • I set a description on the library target.
    • I set a library target to point at the "flat_renderer" target, which is the library that consumers will use when they use this library.
    • I removed the APPLICATION.make as the "root class" because this is a library and not a program to be executed.
    • All testing code that is in APPLICATION will need to be moved to or recreated in ?_TEST_SET class(es) so that testing can easily be performed from Auto Test.

Larry Rix

unread,
Aug 26, 2018, 10:39:09 AM8/26/18
to Eiffel Users
This is not a true statement. The libraries are included in the flat_renderer library and test target, which provides the library the capacity to render DECIMALs and DATE_TIMEs, DATEs, and TIMEs.

What this does not mean is that the consumer of the library must have the decimal and time libraries included in their projects. It simply means that if they do, they can render objects of those types using the flat_renderer library.

Does that make sense?


Kind Regards,

Larry

williams Lima

unread,
Aug 26, 2018, 10:41:34 AM8/26/18
to Eiffel Users
Yes. I understand now. so everything looks fine. :)

Thanks
Williams

Larry Rix

unread,
Aug 26, 2018, 10:43:32 AM8/26/18
to eiffel...@googlegroups.com
Perfect! Happy to know we're on the same page! :-)

Larry Rix

unread,
Aug 26, 2018, 2:01:26 PM8/26/18
to Eiffel Users
Williams,

Please take a look at my lrix branch of the code, download the repo, and open it in the test target. Run the tests. You ought to find that both tests pass (i.e. the ad-hoc test I created and the test-1 that you created and I transferred to the TEST_SET).

The other tests in the APPLICATION class will need to be likewise transferred to the TEST_SET, but I will leave that work for you to do following the example I provided in the first one.

PLEASE NOTE: I corrected some moderate design flaws and bugs, which I found by following the TDD-paradigm (write the failing test first and then correct the code until the test passes). (TDD = Test Driven Development).

FOR EXAMPLE: The {DECIMAL} values were not rendering correctly, because the code for {NUMERIC} was getting ahead of it, which generated a call to the TUPLE version of the out for DECIMAL rather than the correct call to out.


Happy Eiffeling! :-)


Kind Regards,

Larry Rix

Larry Rix

unread,
Aug 26, 2018, 2:14:37 PM8/26/18
to Eiffel Users
Williams,

I have completed the transfer of the first test from APPLICATION to ?_TEST_SET. Please move the remaining tests at your convenience.

I will work towards a version of this (perhaps visitor pattern) that outputs JSON and then we can move on to others as Alex suggested.


Kind Regards,

Larry Rix

williams Lima

unread,
Aug 26, 2018, 2:22:33 PM8/26/18
to eiffel...@googlegroups.com
Ok.

regards

Williams

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

Larry Rix

unread,
Aug 26, 2018, 2:34:40 PM8/26/18
to eiffel...@googlegroups.com
Alex,

Looking at the inheritance structure off of READABLE_INDEXABLE, I think the INDEXABLE [G, H] is well covered. So, structures like ARRAY and ARRAYED_LIST are output just like hash table, except the keys are INTEGER instead of HASHABLE.



Larry Rix

unread,
Aug 26, 2018, 8:45:44 PM8/26/18
to Eiffel Users
Completed almost all of the suggested changes by the Eiffel Inspector on the test target.

Please pull down most recent code from my GitHub branch of FLAT_RENDERER.


Kind Regards,

Larry

Alexander Kogtenkov

unread,
Aug 27, 2018, 3:22:21 AM8/27/18
to eiffel...@googlegroups.com
Clearly, all descendants of READABLE_INDEXABLE are covered, but not all descendants of ITERABLE that is an ancestor of READABLE_INDEXABLE.

Alexander Kogtenkov


Larry Rix <lar...@moonshotsoftware.com>:

Larry Rix

unread,
Aug 27, 2018, 7:23:10 AM8/27/18
to eiffel...@googlegroups.com
My mistake. I was recalling INDEXABLE and not ITERABLE.

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

--

Larry Rix

unread,
Aug 27, 2018, 7:34:00 AM8/27/18
to eiffel...@googlegroups.com
Looking at ITERABLE, I am not sure we need to step that far back in the inheritance model.

Items like ARGUMENTS, ARGUMENTS_32, INDEXABLE_ITERATION_CURSOR, and STRING_ITERATION_CURSOR do not look particularly interesting given the scope of the need.

Moreover, ITERABLE lacks needed routines (i.e. lower, upper, etc.) used by the code currently.

Do you have a proposed design that would allow us to use ITERABLE? It only has one feature (new_cursor) although it says that it can be iterated using the across loop.





Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

On Mon, Aug 27, 2018 at 3:22 AM, 'Alexander Kogtenkov' via Eiffel Users <eiffel...@googlegroups.com> wrote:

--

Larry Rix

unread,
Aug 27, 2018, 8:01:16 AM8/27/18
to Eiffel Users
YAY! ... I was able to get ITERABLE to work using the same basic logic Williams used for READABLE_INDEXABLE. There were some minor alterations, but at the end of the matter, all of the tests pass and we now have coverage starting at ITERABLE.

Thanks, Alex!


Cheers,

Larry

williams Lima

unread,
Aug 27, 2018, 8:06:37 AM8/27/18
to eiffel...@googlegroups.com
It only gets better!

Congratulations Larry.

Williams

--

Larry Rix

unread,
Aug 27, 2018, 8:13:08 AM8/27/18
to eiffel...@googlegroups.com
Here is what it looks like now (below). The following apply:

  • Switched from `k' to `i' — I have learned to read `i' and `index'.
  • Expanded abbreviations like `al_ht' to `al_hash_table' — this is a readability and understandability matter for me (code style).
  • `from' in `across' — The from in the across loop has the purpose of a block of preparatory code. This is how one knows `i' is about the loop (as opposed to setting before the loop).
  • Trailing comma — The trailing comma code is repeated for each Type other than a subordinate ITERABLE, which gets a new-line. The code used to have an if-then afterwards, which added it unless the item was last in the list. This was okay when the object being traversed was READABLE_INDEXABLE, but ITERABLE does not have the required features needed, so I changed the logic.



Larry Rix

unread,
Aug 27, 2018, 8:14:19 AM8/27/18
to Eiffel Users
Happy to do so! Thanks to Alex for pressing the matter once again to get me to look more closely.

williams Lima

unread,
Aug 27, 2018, 8:17:49 AM8/27/18
to eiffel...@googlegroups.com
Larry,
just for a style matter. Is it possible to place the if for ITERABLE as the last one!?

I would like to have all 'basic' cases treated first and leave the recursive call to be the last.

Williams

On Mon, Aug 27, 2018 at 9:14 AM, Larry Rix <lar...@moonshotsoftware.com> wrote:
Happy to do so! Thanks to Alex for pressing the matter once again to get me to look more closely.

--

Larry Rix

unread,
Aug 27, 2018, 8:50:09 AM8/27/18
to Eiffel Users
Re: ITERABLE last — yes. Handled. However—some of the basic type must be handled in particular order. For example: DECIMAL must come before NUMERIC because of the `out' differences between them (i.e. DECIMALs have output routines that general NUMERICs call incorrectly on DECIMAL).

I also started adding breaking tests, which revealed some moderately interesting bugs, which are now resolved and the code is checked in. Pull new code.



On Monday, August 27, 2018 at 8:17:49 AM UTC-4, williams Lima wrote:
Larry,
just for a style matter. Is it possible to place the if for ITERABLE as the last one!?

I would like to have all 'basic' cases treated first and leave the recursive call to be the last.

Williams
On Mon, Aug 27, 2018 at 9:14 AM, Larry Rix <lar...@moonshotsoftware.com> wrote:
Happy to do so! Thanks to Alex for pressing the matter once again to get me to look more closely.

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Larry Rix

unread,
Aug 27, 2018, 9:09:44 AM8/27/18
to Eiffel Users
Williams,

There is new code to fetch.

  • Found more breaking tests, which resulted in small design changes. Now handles Void targets.
  • Name changes for better semantics.

Larry Rix

unread,
Aug 27, 2018, 4:24:26 PM8/27/18
to Eiffel Users
New code to fetch from GitHub:

  • Basic Types Tests — Added tests for basic types, which revealed bugs. I may have already shared that.
  • Dump Range — I was talking with an old friend and colleague about our work, and in that discussion realized that sometimes one has "big data" and only wants to dump a small range of the data (for whatever reason). So—I added a `dump_range' feature that does precisely that. Please look at the code and the tests to see examples of this feature being exercised.
  • More Contracts — from time to time, I like to put on my "contractor hat" and start looking at the code and asking the question: "What can I add contracts to improve the safety and Client-Supplier relationships of this code?" What ends up happening is that I can typically squeeze out a few contracts that make sense. Sometimes, the contracts that get added result in uncovering bugs, which did happen in this case. I also discover contracts that I'd like to write, but don't see how at the present moment, which makes me sit with the code a little longer to weigh the value of the contract vs the expense of the contract (both my hours and computational expense).
You will find that I have added all of the above, plus updated some comments and notes along the way as well.


Cheers,

Larry

williams Lima

unread,
Aug 27, 2018, 4:51:07 PM8/27/18
to eiffel...@googlegroups.com
Great.
The Dump Range looks very convenient.
"More Contracts" - I like your approach to programming. A couple of days
ago, just when I started learning Eiffel, I read an article by Prof. Bertrand Meyer where he said
that once someone learns Eiffel the person never comes back to old programming languages/practices.
After some interaction with people here in the Eiffel users forum that is exactly the feeling that I have.

Now, I'm working on an iterative version of the routine dump_iterable. I'm almost finished.
It should free us of any fear regarding blowing up the stack.

regards
Williams


--

Larry Rix

unread,
Aug 27, 2018, 6:55:35 PM8/27/18
to eiffel...@googlegroups.com
Williams,

The cycle is pretty straight forward. Eiffel has a core notion: Do not directly or indirectly create BUGS! Indirect bug creation usually happens because the language notation allows a programmer to do things that are legal in the compiler, but buggy or difficult to maintain because the code is brittle and bugs are hidden and ignorant programmers blunder into them because they don't know or don't care or are filled with pride ("I will never make that mistake!"). Thankfully, Bertrand (and others) have taken a protectionist attitude towards the language, method, and IDE and constantly ask, "How can things go wrong?"

This has become a sort of core belief in the Eiffel community. Don't get me wrong: One can still write crappy and buggy code in Eiffel. However—if you're thoughtful and grow in what you know, you'll produce far less buggy code in Eiffel than just about any other language I know. About the only real savior in other languages are good, strong, healthy, long-lived libraries, which have had the bugs beat out of them over years. However, that doesn't save you very much when you write that zero-based for-loop in Java and forget that you're starting at zero instead of one.


In a step-wise manner, I cycle through the following:

  • Design / Discuss
    • Implement each Design with code + tests --> Design Experiments
    • Pick one --> Final Design
  • Write Code + Tests (use TDD + DbC) --> Usable System(s)
  • Review + Update
    • Review Semantics — review names and naming. Well-named things create fewer bugs and better readability, understandability, and quick comprehension.
      • Try getting names right to start with, but know that you will still find 20% of named things you'll want to change on your first review pass.
    • Review Style  — coding standards for things like code layout, feature group naming, tabs, spaces, indenting, white-space, and so on.
      • Coding standards and style are there to make your life and comprehension quicker and better.
      • One ought to be able to look at Eiffel code and NOT be able to easily discern the author.
    • Review Inheritance  — sometimes descendant code can move back to a high ancestor and sometimes new classes emerge for better organization.
      • Move code back?
      • Need new classes?
      • Is the design better off if you use a has-a rather than an is-a construct?
    • Review Contracts  — better and more meaningful contracts help catch bugs early and often so a "contract review" is critical to do from time-to-time.
      • You can write contracts that are too restrictive
      • You can write contracts that are inappropriate. This is mainly true when your code has requirements which depend on external entities you cannot control (like users).
      • Pay attention to loop variants and invariants!
      • Class invariants are the strongest and best contract you can write. Shoot for these first!
      • Don't write
    • Run/Do Analysis
      • Use the Eiffel Studio "Project --> Analyze Current Target" test analyzer tool liberally and often!
      • Get a more experience programmer to review your code sooner rather than later!
    • Review Documentation  — as the code solidifies, one can really zero in on writing terse, but good documentation (one might also include a good glossary of terms in notes).
      • Review feature comments (the Eiffel Studio code analyzer will tell you if you are missing feature comments)
      • Make comments as terse as possible, but do not sacrifice understandability and readability!
      • Review notes: 
        • Add EIS links where helpful.
        • Define terms where needed (a code reviewer can help you spot terms they don't have well defined)
        • Add warnings or see-also's where helpful
        • If needed, describe your design
        • If needed, describe design choices you rejected and why—this might save you from someone trying to be clever who thinks they have a better mouse-trap and does not know why you rejected their "clever design".
        • Do not just give a description, but describe the purpose and even how you get that purpose handled. Be careful to not just write pseudo-code.
        • (NOTE: If you start out with psuedo-code as a part of your design effort, do so as comments, not notes, and then code-your-comments, removing comments as you code because of the Self Documenting Principle).
    • Refactor  — sometimes routines need to be broken apart, code isolated in other commands and queries, and generally moved to appropriate places (reuse, reuse, reuse!).
    • Review Testing — continually be on the lookout for good testing
      • Do not over-test — you have to maintain that test once it is written and that requires time, labor, and money!
      • Do not write a test for what is covered in a contract — that just misses the point of Design-by-Contract in the first place!
      • Review already existing tests to see if they can be moved into the code as contracts instead!
      • Generally — do not write client check contracts for what a supplier ensures in its post-condition! (that is a waste of precious computing resources)
      • Generally — write tests (TDD) as the highest interface level you can and write contracts from there to the lowest levels you can, which will result in less TDD test code to maintain! (saving you time and money)
      • Generally — split out prep code from test code, isolating test prep code in its own routines (which can potentially be reused by other tests).
      • Know the difference between unit testing and regression testing and how it looks in Eiffel and Auto Test.
      • If you're on a team of more than 1 programmer — have a nightly or periodic automated testing cycle with failed test reporting. Handle failed tests before moving on to new coding tasks!
    • Review Data Structures
      • Eiffel base library (and others) have a wealth of great data structures. You may find that you need an ARRAYED_STACK instead of an ARRAYED_LIST or ARRAY. Study these. Know them. They help!
      • Your own structures may not be the best or most efficient. This is a hand-in-hand cousin with Refactor (above).
    • Review Performance — use the Eiffel Profiler tool to stress test your code.
      • The Profiler results will tell you where your code is spending most of its time. You'd be surprised by how easily you can improve the efficiency of your code by periodically examining it as it runs using this tool!
      • The Profiler results will lead you to:
        • Refactor
        • Review Contracts — you might have expensive contracts that you either don't need or can write better!
        • Review Analysis — the analyzer might point out computationally expensive code!
        • Review Data Structures — you might find a better, faster, cheaper data structure or an easier method for traversal and so on!
  • Training + Knowing
    • Compiler — be thou a good programmer and know thy compiler! (from the Book of Eiffel, chapter 1, verse 1) — the ECMA specification for Eiffel is a healthy thing to read!
      • Behind every great IDE and Method is an even greater compiler!
    • IDE — know your IDE nearly as well as you know your compiler! See if your design, code, and tests play well in it!
    • Eiffel Method — know the Eiffel Method (yes, there is such a thing)! See if your design, code, and tests agree!
    • Review other peoples code — study the Eiffel libraries (e.g. the base library is an excellent study guide in and of itself)


williams Lima

unread,
Aug 27, 2018, 7:11:07 PM8/27/18
to eiffel...@googlegroups.com
Thank you very much Larry. 
You should put these guidelines somewhere in the Eiffel Community site.

best regards
Williams

williams Lima

unread,
Aug 27, 2018, 8:15:51 PM8/27/18
to Eiffel Users
I'm working on an iterative version (alternative to the recursive one) of the routine that visits the elements of the data structure.
I created another branch to experiment with it:

The code passed all tests but the one for Basic Types.

regards
Williams

Larry Rix

unread,
Aug 27, 2018, 9:07:47 PM8/27/18
to eiffel...@googlegroups.com
Works for me. Try clean compiling it.

Larry Rix
Moonshot Software
Rocket science for everyone!
Savannah, GA

Finnian Reilly

unread,
Aug 28, 2018, 5:16:43 AM8/28/18
to Eiffel Users
Hey guys,
this is excellent work you are doing on the renderer project. I salute you.

If you want to do some work on it we can communicate directly by email in order
to not pollute the forum. And of course make some updates here when convenient.
 
But so as not to pollute this general forum might I suggest that you do project coordination via github, which has an excellent issue handling mechanism that functions a bit like a forum, i.e. once an issue is raised, anyone who is a github member can see and add comments to it, not just the contributors.


It has a number of advantages over google groups.
  • All the comments and issues are permanently linked with the project code for posterity
  • Better support for syntax highlighting code fragments in comments (using wiki-markup)
  • It has support for emoticons (if you like those)
  • You can manage the status of an issue (open/closed)

williams Lima

unread,
Aug 28, 2018, 6:17:01 AM8/28/18
to eiffel...@googlegroups.com
I agree.

Williams

Reply all
Reply to author
Forward
0 new messages