Help with segmentation fault

269 views
Skip to first unread message

Jimmy Johnson

unread,
Dec 12, 2021, 3:35:08 PM12/12/21
to Eiffel Users
I sure would appreciated someone taking a look at this segmentation fault and maybe provide a fix.  I've recreated the problem in the attached small example. 

thanks,
jjj
segfault.zip

lrix

unread,
Dec 15, 2021, 8:06:43 AM12/15/21
to Eiffel Users
As a general aside—I find that segfaults are generally resolved using the following:

1. While running Auto-test tests, I will attempt to preempt segfaults by doing a Freeze compile. I will certainly do this at the first encounter of a segfault.
2. If the Freeze compile fails to clear the error, I will then do a clean compile.
3. If the clean compile fails to clear the segfault, then I will delete the EIFGENs.
4. If all of the above fails to clear the segfault, then there is generally a deeper problem. Usually, the problem is either with poorly designed code on my part or it is improper use of Eiffel library code.
5. The final place where I have found segfaulting is when I am using Eiffel on the Raspberry Pi to control electronics and I either use library C code improperly or the electronics is off, not working, or not hooked up.

That is the full range and resolutions I have encountered to date for segfaulting code.


Kindest regards,

Larry Rix

r...@amalasoft.com

unread,
Dec 15, 2021, 9:37:19 AM12/15/21
to eiffel...@googlegroups.com
Hi Larry (et al)
Good tips, but they don't apply in this case.  I build a new project with the code and ecf included in the original email and compiled it cleanly (a brand new project).  It still seg faulted.
The next step I'd recommend for such a case is to run it in the debugger from the C compiler used.  For better results (depending on the C compiler), it might be necessary to add the -g option to the C compilation flags first (to suppress symbol table removal).

It would be nice, though rarely needed, to have such an option in estudio (as finalize option and an execute option)
R
--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/ed901655-3494-44e7-af34-142cfb52e958n%40googlegroups.com.

clan...@earthlink.net

unread,
Dec 16, 2021, 1:00:04 AM12/16/21
to Eiffel Users
I don't think you even need a c level debugger. You can see problems appear in your fields shown in the debugger before it crashes.

I think the declaration of recomputed_cost as numeric causes the grief, because you are in a strange world where the code is using a reference where you intend to use an Integer.

I saw a huge number in a integer field which looked much like a pointer, and a Result that was void, when it should have been an integer.

I would get rid of the anchors everywhere and be more careful with which values are references and which are expanded. Remember there are Integer_refs.

Carl

Ulrich Windl

unread,
Dec 16, 2021, 3:00:43 AM12/16/21
to eiffel...@googlegroups.com
>>> <r...@amalasoft.com> schrieb am 15.12.2021 um 15:37 in Nachricht
<20211215073715.cf48dd763fcaf5d4...@email25.godaddy.
om>:
> Hi Larry (et al)
> Good tips, but they don't apply in this case. I build a new project with the

> code and ecf included in the original email and compiled it cleanly (a brand

> new project). It still seg faulted.

For current Linux systems using systemd, "coredumpctl gdb" may be the easiest
way to get details; there should also be a syslog message in the journal
("journalctl").
https://groups.google.com/d/msgid/eiffel-users/20211215073715.cf48dd763fcaf5d

> 42559c6c92f6fc53b.98be62002e.wbe%40email25.godaddy.com.


Jimmy Johnson

unread,
Dec 16, 2021, 9:21:26 PM12/16/21
to Eiffel Users
On Wednesday, December 15, 2021 at 11:00:04 PM UTC-7 clan...@earthlink.net wrote:
I don't think you even need a c level debugger. You can see problems appear in your fields shown in the debugger before it crashes.

I think the declaration of recomputed_cost as numeric causes the grief, because you are in a strange world where the code is using a reference where you intend to use an Integer.

Yes.  I noticed that `twin' is called for the assignments. ??   
I added lines to make the calls to path.cost more explicit, and I see what you mean.
                         create path
                        c := path.cost;
                        Io.put_string ("{APPLICATION}.make:  cost = " + c.out + "%N")
                        c := path.cost;
                        Io.put_string ("{APPLICATION}.make:  cost = " + c.out + "%N");
                        path.set_my_cost (1000);
In/during the first execution of `cost', the execution goes where I expect:
        frozen cost: like recomputed_cost
              do
                        if is_dirty then
                                Result := recomputed_cost
                                set_clean
                        else
                                Result := cost_imp     <-------      executed when `is_dirty'
                        end
                end
Because `cost_imp' is declared as "attribute   Result := recomputed_cost", feature  'recomputed_cost' is called to calculate the initial value of `cost_imp'..., but..., `recomputed_cost' *assigns* a value to `cost_imp'.  I'm thinking this could be [one of] the problem(s).

I saw a huge number in a integer field which looked much like a pointer, and a Result that was void, when it should have been an integer.

I noticed that as `cost' ends the value of `cost_imp' (which was zero as expected) goes to some large integer value, and `my_cost' which supposedly was not even touched becomes 32712.   ???
 
I would get rid of the anchors everywhere and be more careful with which values are references and which are expanded. Remember there are Integer_refs.

Carl, I'm not sure how to do that.  This example was distilled from a larger library for graphs (nodes, edges, paths).  Class WALK (should be named PATH, but that conflicts with base class PATH), represents a series of edges explored when traversing a graph.  The cost is simply the number of edges.  In the descendant, WEIGHTED_PATH [C -> ...], the cost should be calculated as the sum of the edge costs along the path.  It must be anchored to C because the graph classes serve as generic containers.
 
Thanks for the insight.  It directed me to dig a little deeper, so perhaps I am making progress.
jjj

lrix

unread,
Dec 17, 2021, 7:00:26 AM12/17/21
to Eiffel Users
The issue is NUMERIC instead of INTEGER. The code is counting edges, which are integer values. The cannot be REAL, so NUMERIC is not warranted. I changed the type to INTEGER and the program runs successfully.

lrix

unread,
Dec 17, 2021, 7:08:31 AM12/17/21
to Eiffel Users
Furthermore—this goes to my original list of suggestions with regard to segfaulting. In particular—item #4 ...


4. If all of the above fails to clear the segfault, then there is generally a deeper problem. Usually, the problem is either with poorly designed code on my part or it is improper use of Eiffel library code.

This appears to be the case with this code. Generics mixed with more abstract types like NUMERIC was a nearly immediate code smell to me. So, the quickest way to test that theory was to change from NUMERIC to INTEGER and see if it compiled. It did. So, the next step was to run the program and see if the segfault persisted. It did not.

Moral of the story—you did the right thing by reaching out. I also find that I can get horse blinders on myself and it takes another person to spot my error or give me new ideas and approaches. My accounting professor in school called it Accountants Disease. When one looks at a column of numbers and cannot see the error in their addition any longer. :-)


Jimmy Johnson

unread,
Dec 17, 2021, 1:26:16 PM12/17/21
to Eiffel Users
Larry,
Comments are greatly appreciated.

On Friday, December 17, 2021 at 5:08:31 AM UTC-7 lrix wrote:
This appears to be the case with this code. Generics mixed with more abstract types like NUMERIC was a nearly immediate code smell to me. So, the quickest way to test that theory was to change from NUMERIC to INTEGER and see if it compiled. It did. So, the next step was to run the program and see if the segfault persisted. It did not.
 
Perhaps it's poorly designed, but...the graph classes from which this example are derived are generic containers.  If I select INTEGER as the type then a user can never have edges/paths that have REAL values for the cost.

 
Moral of the story—you did the right thing by reaching out. I also find that I can get horse blinders on myself and it takes another person to spot my error or give me new ideas and approaches. My accounting professor in school called it Accountants Disease. When one looks at a column of numbers and cannot see the error in their addition any longer. :-)

In the flying word its "target fixation"-- I keep looking at one thing when the error is somewhere else.

I agree, and that is why this list is so great--having someone else look at it.
jjj
 

clan...@earthlink.net

unread,
Dec 17, 2021, 7:27:44 PM12/17/21
to Eiffel Users
I think that instead of NUMERIC as the type of 'recomputed_cost' you would use your weight class. Since it is generic, you can have the NUMERIC and COMPARABLE dependencies and all the convenient arithmetic as features. You can use INTEGER, REAL, or any other class you dream up as part of its implementation.

Carl

lrix

unread,
Dec 19, 2021, 7:44:38 AM12/19/21
to Eiffel Users
Jimmy,

I generally hold phrases like poorly designed for myself because when it comes to the code of other people, I do not know what you know, nor what your goals are with the same precision and detail that you do. So—I was not trying to imply your design is poor. The best I can do in this case is to simply point out that I changed from NUMERIC to INTEGER and the world was well from compile to run.

On the matter of design, my interest is piqued. From what little I know of graphs with nodes and edges, I am unsure as to how one can have fractional (REAL) edge counts. School me?

Jimmy Johnson

unread,
Dec 19, 2021, 1:32:07 PM12/19/21
to Eiffel Users
No offense taken.  That's what this list if for.  I would rather have any feedback than to be ignored.  It is also nice when the discussion leads to an answer to the original question.  (See "Where can I get Eiffel to test-drive?")  It might be poorly designed, but I have run so far down this rabbit hole that it is hard for me to change gears.

An edge can have a weight (i.e. it takes effort to traverse the edge.)  Think miles between two cities.  A path (a sequence of edges) also has a cost to traverse.  If the edges do not have weights then the cost to traverse the path could simply be the number of edges in the path; if the edges in the path do have weights, then the path-traversal cost becomes the sum of the edge weights.

Jimmy Johnson

unread,
Dec 19, 2021, 1:55:28 PM12/19/21
to Eiffel Users
I removed the self-initialization from `cost_imp' and redefined `default_create' to set the value.  From WALK:
        default_create
                        -- Create an instance
                do
                        cost_imp := recomputed_cost
                end
If I step into this feature, it seems that `recomputed_cost' executes fine, returning INTEGER equal to zero.  But the assignment forces a call to `twin' from INTEGER_32, for which the result is zero.  But after the assignment the debugger shows:
Screen Shot 2021-12-19 at 11.48.50 AM.png
At this point `cost_imp' is obviously wrong, and `my_cost', which was not even touched should be zero.  So why is twin called?  Back to the expanded versus reference type issue?
jjj 

SVHarvey (Optus)

unread,
Dec 20, 2021, 1:09:31 AM12/20/21
to eiffel...@googlegroups.com
and complex number weights could of instance mimic electrical circuitry where impedances are complex.

Simon

On 20 Dec 2021, at 05:55, Jimmy Johnson <eiffe...@gmail.com> wrote:

I removed the self-initialization from `cost_imp' and redefined `default_create' to set the value.  From WALK:
        default_create
                        -- Create an instance
                do
                        cost_imp := recomputed_cost
                end
If I step into this feature, it seems that `recomputed_cost' executes fine, returning INTEGER equal to zero.  But the assignment forces a call to `twin' from INTEGER_32, for which the result is zero.  But after the assignment the debugger shows:
<Screen Shot 2021-12-19 at 11.48.50 AM.png>
At this point `cost_imp' is obviously wrong, and `my_cost', which was not even touched should be zero.  So why is twin called?  Back to the expanded versus reference type issue?
jjj 


--
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.

Jimmy Johnson

unread,
Dec 20, 2021, 1:21:52 PM12/20/21
to Eiffel Users
On Sunday, December 19, 2021 at 11:09:31 PM UTC-7 sharvey wrote:
and complex number weights could of instance mimic electrical circuitry where impedances are complex.

Simon
 
Right now I restrict the generic parameter to NUMBERIC and COMPARABLE, but complex types are not comparable, right?  Sorting edges/nodes/paths seems to make other computations simpler/faster, maybe.
jjj

lrix

unread,
Dec 20, 2021, 5:05:19 PM12/20/21
to Eiffel Users
From the descriptions being offered, I can now understand having fractional edge counts (e.g. REAL or DECIMAL). So, this is making better sense to me. In that light, it seems that Jimmy's design thought is in the right direction, but explaining that in code in a way that the compiler is happy with and meets the design goal is the matter at hand. It may well be that such code has uncovered a compiler bug or perhaps a compiler design flaw or limit. Either way—that is something for Eiffel Software and not for a hack like me.

Having said that—I am intrigued enough to play with it some more this evening. I have a couple other chores at hand to take care of, but I will do my best to give this some focus.


Kindest regards,

Larry Rix

Philippe K

unread,
Dec 21, 2021, 8:30:08 AM12/21/21
to Eiffel Users
Hi Larry,

Thank you for giving your insights into the possible origin of the "segmentation fault" type problems. It is very useful for newcomers.

Beyond this immediate help, your answer raises, in my opinion, several points and I venture to play devil's advocate:

1) Is it normal that the compiler is not able to detect these problems? Are they perhaps too complex to discover?

2) Is this architecture of a compiler based on both executed and compiled code still relevant today?

The objective of this architecture was to save time in the development and testing cycle.  This choice, which seems to go back to the very origins of the Eiffel software compiler (1985)is it still valid today with the spectacular increase in the power of processors since that time?
This choice of compiler architecture does not seem to have been widespread. Unless I am mistaken, the SmartEiffel and GoboEiffel compilers seem to have always performed very well
This choice of compiler architecture does not seem to have been widespread. Unless I am mistaken, the SmartEiffel and GoboEiffel compilers seem to have always performed very well without
this mechanism. Moreover, even in those remote days, there were commercial compilers with spectacular performance. I'm thinking of
TurboPascal, a real compiler (without C code generation), very fast with an incredibly low memory footprint (but it's true that Pascal is not as high level than the Eiffel language but still...)

I have the impression that this kind of compiler architecture can be a source of errors and requires special attention for the user without any real benefits today given the advances in the hardware.

3) the use of high classes in a hierarchy seemed to be a possible source of issues. The purpose of these classes is primarily to abstract and factorise a number of features for the benefit of descendant classes. In a context of using classes from libraries, it goes without saying that the "concrete" classes, i.e. the terminal classes, must be used. Wouldn't it be better to prevent the use of these "high" classes by an export/non-export (private) clause. I only mention this point in passing, but I don't want to re-open the debate on namespaces... a heated debate that has occurred several times in this community.

Philippe.

lrix

unread,
Dec 21, 2021, 9:29:46 AM12/21/21
to Eiffel Users
Philippe,

Clearly, your response goes beyond my knowledge boundaries and capacity to respond in kind. However—after I sent the message above (yesterday), a more pragmatic solution came to me and you have suggested (or at least hinted at) it as well. Namely—to make classes using NUMERIC Generics as deferred (abstract) and then creating appropriate implementations with more specific Generics. My guess—in the case of Jimmy's code example—is that this would be necessary anyhow if one used the DECIMAL class vs INTEGER or REAL, because DECIMAL is not an expanded type.

For example: I have re-downloaded Jimmy's example and I am working with in the 21.11 beta (for grins and giggles).

After an initial clean compile—the running code does (in fact) still segfault. So—the newest compiler did not resolve the issue.

I then modify WALK and WEIGHTED_PATH with INTEGER in place of NUMERIC and freeze compile the code and run it again. As before, the program successfully executes with no segfault.

Now—it is time to implement the idea of making WALK and WEIGHTED_PATH deferred and pushing implementation of recomputed_cost down to a concretely implemented descendent class that I will call MY_WEIGHTED_PATH.

In APPLICATION, the path feature becomes type MY_WEIGHTED_PATH (e.g. path: MY_WEIGHTED_PATH).

In WALK, the class is now deferred and the create clause is removed. The class WALK now becomes WALK [G -> NUMERIC]. Also, the recomputed_cost and the cost_imp types are now G Generics instead of being directly typed. Finally, the recomputed_cost feature is deferred, leaving the ensure contract block as-is. This will push the implementation down to MY_WEIGHTED_PATH.

In WEIGHTED_PATH, the class is now deferred and the create clause is removed a well. The C Generic is left as NUMERIC, but the inherit of WALK now becomes WALK [C], which merely restates the Generic in WALK, but also adds a Generic for COMPARABLE as Jimmy implemented it. No changes there. The only other change is the complete removal of the recomputed_cost feature, which is held as deferred in WALK and will gets it implementation in MY_WEIGHTED_PATH.

Finally, I create the MY_WEIGHTED_PATH (see end of this message).

I then freeze compile this code and run it successfully with no segfault.

That this new code works tells me a few things:
  • Straight forward design
  • Lack of Generic minefield for the compiler
  • Easily understandable deferred feature implementation
I have attempted to attach a new ZIP file, but Google keeps giving me an error. Instead, I will copy and paste each file.

---
note
        description: "[
                Trying to reproduce a segmentation violation in
                the graph classes.

                This gives a "Segmentation Fault" in the last line
                of `make' when calling `cost'.  This call to `cost'
                attempts to return the memoized value computed in the
                previous call to `cost'.
                ]"
class
        APPLICATION

create
        make

feature {NONE} -- Initialization

        make
                        -- Run application.
                do
                        io.put_string ("%N%N%N%N%N%N")
                        io.put_string ("Begin testig %N")
                        create path
                        io.put_string ("{APPLICATION}.make:  cost = " + path.cost.out + "%N")
                        io.put_string ("{APPLICATION}.make:  cost = " + path.cost.out + "%N")
                        path.set_my_cost (1000)
                        io.put_string ("{APPLICATION}.make:  cost = " + path.cost.out + "%N")
                                -- segmentation fault in {WEIGHTED_PATH}.`cost'
                        io.put_string ("{APPLICATION}.make:  cost = " + path.cost.out + "%N")
                end

feature {NONE} -- Implementation

        path: MY_WEIGHTED_PATH
                -- Object to test

end
---
note
        description: "[
                An ordered collection of edges beginning at a `start_node'.
                Edges can only be added and        removed from the end.
                This is to be used with a {GRAPH}.
                ]"
        author:                "Jimmy J. Johnson"
        date:                "8/21/21"

deferred class
        WALK [G -> NUMERIC]

feature -- Access

        frozen cost: like recomputed_cost
                        -- The price of exploring Current
                        -- The default returns the number of edges
                        -- Redefine `recompute_cost' assigning result to `cost_imp'
                        -- to change symantics of this feature.
                do
                                -- Memoize the calculation

                        if is_dirty then
                                Result := recomputed_cost
                                set_clean
                        else
                                Result := cost_imp
                        end
                end

feature -- Status report

        is_dirty: BOOLEAN
                        -- Has Current changed since last call to `recomputed_cost'?

feature -- Status setting

        set_dirty
                        -- Make Current `is_dirty'
                do
                        is_dirty := true
                end

        set_clean
                        -- Make Current not `is_dirty'
                do
                        is_dirty := false
                end

feature {NONE} -- Implementation

        recomputed_cost: G
                        -- Calculate the `cost', memoizing the result
                        -- in `cost_imp'.
                deferred
                ensure
                        not_dirty: not is_dirty
                end

        cost_imp: G
                        -- Holds the cost calculated in `recompute_cost'
                        -- and anchor for `cost'
                attribute
                        Result := recomputed_cost
                end

end
---
note
        description: "[
                A path which holds edges of type {WEIGHTED_EDGE}.
                Each edge has a `cost' of type C.
                        ]"
        author:    "Jimmy J. Johnson"
        date:      "10/27/21"
        copyright: "Copyright (c) 2021, Jimmy J. Johnson"
        license:   "Eiffel Forum v2 (http://www.eiffel.com/licensing/forum.txt)"

deferred class
        WEIGHTED_PATH [C -> {NUMERIC,
                                                COMPARABLE rename default_create as comparable_default_create end}
                                                create default_create end]

inherit

        WALK [C]

feature -- Access

        my_cost: like recomputed_cost
                        -- Value as set
                attribute
                        Result := recomputed_cost
                end

feature -- Element change

        set_my_cost (a_cost: like recomputed_cost)
                        -- Change `my_cost'
                do
                        my_cost := a_cost
                        set_dirty
                end

end
---
note
        description: "An INTEGER implementation of WEIGHTED_PATH"

class
        MY_WEIGHTED_PATH

inherit WEIGHTED_PATH [INTEGER]

create
        default_create

feature {NONE} -- Implementation

        recomputed_cost: INTEGER
                        --<Precursor>
                do
                        Result := my_cost
                        cost_imp := Result
                        set_clean
                end

end
---

lrix

unread,
Dec 21, 2021, 9:56:44 AM12/21/21
to Eiffel Users
To prove to myself that my solution actually works, I created two more classes as descendants of WEIGHTED_PATH [C -> NUMERIC]:

MY_WEIGHTED_REAL_PATH [REAL] and MY_WEIGHTED_DECIMAL_PATH [DECIMAL] (after adding the decimal library to the project).

The REAL version was just as straight forward as the INTEGER version. However, the DECIMAL version took some extra code because the class is not an expanded type (I wish it was and could join its brethren without special handling). Nevertheless—here are those classes:

---
note
        description: "A REAL version"

class
        MY_WEIGHTED_REAL_PATH

inherit
        WEIGHTED_PATH [REAL]


create
        default_create

feature {NONE} -- Implementation

        recomputed_cost: REAL

                        --<Precursor>
                do
                        Result := my_cost
                        cost_imp := Result
                        set_clean
                end

end

---
And the DECIMAL version is ...

---
note
        description: "A DECIMAL version"

class
        MY_WEIGHTED_DECIMAL_PATH

inherit
        WEIGHTED_PATH [DECIMAL]
                redefine
                        default_create
                end

create
        default_create

feature {NONE} -- Initialization

        default_create
                        --<Precursor>
                do
                        create cost_imp.make_from_string ("0.000")

                end

feature {NONE} -- Implementation

        recomputed_cost: DECIMAL

                        --<Precursor>
                do
                        Result := my_cost
                        cost_imp := Result
                        set_clean
                end
end
---

The deferred recomputed_cost feature remains the same in all, which begs the question: Can we push back up? That is a design question for Jimmy to ponder and decide for the moment. I won't do it here.

The real change (of course—and already mentioned) is the additional code needed for the DECIMAL version.

--- OUTPUT ---
Begin testig
{APPLICATION}.make:  cost = 0.000
{APPLICATION}.make:  cost = 0.000
{APPLICATION}.make:  cost = 1000
{APPLICATION}.make:  cost = 1000

Press Return to finish the execution...
--- END OUTPUT ---

Notice that the first two make lines have (in fact) an output value of 0.000, which is the default value chosen in the default_create feature as it is redefined. The last two make lines are INTEGER because they are being set as INTEGER in APPLICATION. Therefore, I will change line #27 to read:

path.set_my_cost (create {DECIMAL}.make_from_string ("1000.000"))

This has the desired effect of modifying the output.

--- OUTPUT ---
Begin testig
{APPLICATION}.make:  cost = 0.000
{APPLICATION}.make:  cost = 0.000
{APPLICATION}.make:  cost = 1000.000
{APPLICATION}.make:  cost = 1000.000

Press Return to finish the execution...
--- END OUTPUT ---

As you can see (above), the last two make lines are 1000.000 as expected. However, this leaves more questions for Jimmy to explore and answer on his own (unless someone here helps). For example—why do a set of DECIMAL features lose their precision by sending an INTEGER value through set_my_cost ? Myself, I am very interested and curious about the answer to that.

Also note: I further modified the WEIGHTED_PATH class with more C Generics, which seemed to make better sense given the overall design choices I am making.


---
note
        description: "[
                A path which holds edges of type {WEIGHTED_EDGE}.
                Each edge has a `cost' of type C.
                        ]"
        author:    "Jimmy J. Johnson"
        date:      "10/27/21"
        copyright: "Copyright (c) 2021, Jimmy J. Johnson"
        license:   "Eiffel Forum v2 (http://www.eiffel.com/licensing/forum.txt)"

deferred class
        WEIGHTED_PATH [C -> {NUMERIC,
                                                COMPARABLE rename default_create as comparable_default_create end}
                                                create default_create end]

inherit

        WALK [C]

feature -- Access

        my_cost: C

                        -- Value as set
                attribute
                        Result := recomputed_cost
                end

feature -- Element change

        set_my_cost (a_cost: C)

                        -- Change `my_cost'
                do
                        my_cost := a_cost
                        set_dirty
                end

end
---

Eric Bezault

unread,
Dec 21, 2021, 10:09:18 AM12/21/21
to eiffel...@googlegroups.com
On 21/12/2021 15:29, lrix wrote:
> For example: I have re-downloaded Jimmy's example and I am working with
> in the 21.11 beta (for grins and giggles).
>
> After an initial /clean compile/—the running code does (in fact) still
> segfault. So—the newest compiler did not resolve the issue.

For what it's worth, I tried to compile Jimmy's original example
with the Gobo Eiffel compiler. Apart from some warnings about
self-initializing attributes, this example seems to compile and
execute fine:

~~~~~~~~~~~~~~~~~~~~~
PS C:\DriveE\gobo\jjj> gec --gc=boehm .\fault_tester.ecf
Degree 6: 0/0/0 0:0:0.083
Degree 5: 0/0/0 0:0:1.404
Degree 4: 0/0/0 0:0:0.074
Degree 3: 0/0/0 0:0:0.109
[VWAB] class WEIGHTED_PATH (WALK,66,2): self-initializing code for
attribue `cost_imp' will never be executed because its type is either
detachable or expanded.
----
[VWAB] class WEIGHTED_PATH (28,2): self-initializing code for attribue
`my_cost' will never be executed because its type is either detachable
or expanded.
----
Degree -2: 0/0/0 0:0:0.059
Degree -3: 0/0/0 0:0:0.094
fault_tester1.c
Degree -4: 0/0/0 0:0:3.434
Total Time: 0/0/0 0:0:5.273
PS C:\DriveE\gobo\jjj> .\fault_tester.exe






Begin testig
{APPLICATION}.make: cost = 0
{APPLICATION}.make: cost = 0
{APPLICATION}.make: cost = 1000
{APPLICATION}.make: cost = 1000
~~~~~~~~~~~~~~~~~~~~~

So it looks like the issue is not in the Eiffel code. It looks rather
like a compiler bug in the EiffelStudio compiler.

Furthermore, when trying to finalized the example with EiffelStudio I
get this C compilation error:

~~~~~~~~~~~~~~~~~~~~~
C:\DriveE\gobo\jjj\EIFGENs\fault_tester\F_code\C20\wa976.h(9): error
C2040: 'F33_7404': 'EIF_REFERENCE (EIF_REFERENCE)' differs in levels of
indirection from 'EIF_INTEGER_32 (EIF_REFERENCE)'
C:\DriveE\gobo\jjj\EIFGENs\fault_tester\F_code\C20\wa976.c(26): error
C2040: 'F33_7404': 'EIF_REFERENCE (EIF_REFERENCE)' differs in levels of
indirection from 'EIF_INTEGER_32 (EIF_REFERENCE)'
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual
Studio\2022\Community\VC\Tools\MSVC\14.30.30705\bin\HostX86\x64\cl.EXE"'
: return code '0x2'
~~~~~~~~~~~~~~~~~~~~~

So it looks like the compiler is confused with the redefinition of the
result type from a reference type to a formal generic parameter whose
associated actual generic parameter is an expanded type.

--
Eric Bezault
mailto:er...@gobosoft.com
http://www.gobosoft.com

lrix

unread,
Dec 21, 2021, 11:06:29 AM12/21/21
to Eiffel Users
@Eric—I wondered if that was the case. I simply do not have your level of experience and knowledge to make such a determination. However, I wonder if the re-worked code that I supplied (above) is (from your point of view and others) an appropriate solution—even if the compiler does have a "bug" with regard to this design.  FWIW—it is not that I thought Jimmy's design was at fault. Perhaps it is more that I wanted a work-around to the segfault and by way of experience with such things in the past, I gravitate to the solution presented (above). Nevertheless—I am really intrigued by your findings! I wonder how Alex, Jocelyn and others at Eiffel Software would weigh in on the subject as you have presented it?

Eric Bezault

unread,
Dec 21, 2021, 11:40:14 AM12/21/21
to eiffel...@googlegroups.com
On 21/12/2021 17:06, lrix wrote:
> @Eric—I wondered if that was the case. I simply do not have your level
> of experience and knowledge to make such a determination. However, I
> wonder if the re-worked code that I supplied (above) is (from your point
> of view and others) an appropriate solution—even if the compiler does
> have a "bug" with regard to this design.

Yes, having class WALK generic and changing the *cost* features in that
class to be of type G was also a workaround that I thought about. The
only difference is that I did:

WALK [C -> NUMERIC create default_create end]

and then replaced:

Result := 99

with:

create Result

Jimmy Johnson

unread,
Dec 21, 2021, 2:56:07 PM12/21/21
to Eiffel Users
On Tuesday, December 21, 2021 at 9:06:29 AM UTC-7 lrix wrote:
(above). Nevertheless—I am really intrigued by your findings! I wonder how Alex, Jocelyn and others at Eiffel Software would weigh in on the subject as you have presented it?

Me too.   jjj 

lrix

unread,
Dec 21, 2021, 5:25:07 PM12/21/21
to Eiffel Users
@Eric—I am surmising that your solution to WALK.recomputed_cost where you create Result instead of deferring means that one only has to redefine that feature in the descendant if needed (perhaps for DECIMAL). Otherwise, it can handle itself using the WALK implementation. If so, that makes good sense to me and pretty well sews up the work-around.

ALSO—with regard to a possible compiler bug, I wonder if the matter could exist deeper—that is—could it be a flaw or ambiguity in the language grammar itself? Perhaps the real goal of Jimmy's design ought to be thought about at the language level first and then brought forward to the compiler (if warranted)? Otherwise—the work around seems adequate to me for day-to-day pragmatic design, code, test, and delivery—yes?

Eric Bezault

unread,
Dec 21, 2021, 6:00:24 PM12/21/21
to eiffel...@googlegroups.com
On 21/12/2021 23:25, lrix wrote:
> ALSO—with regard to a possible compiler bug, I wonder if the matter
> could exist deeper—that is—could it be a flaw or ambiguity in the
> language grammar itself?

I cannot see anything wrong with the language itself here.
Bertrand, Alexander, any thoughts on that?

The fact that it works fine with the Gobo Eiffel compiler
makes me think that it is more likely to be a bug in the
EiffelStudio compiler than a flaw in the language. But
I may be wrong.

Eric Bezault

unread,
Dec 21, 2021, 6:02:59 PM12/21/21
to eiffel...@googlegroups.com
On 21/12/2021 23:25, lrix wrote:
> @Eric—I am surmising that your solution to *WALK.recomputed_cost* where
> you /*create Result* /instead of deferring means that one only has to
> redefine that feature in the descendant if needed (perhaps for DECIMAL).
> Otherwise, it can handle itself using the WALK implementation. If so,
> that makes good sense to me and pretty well sews up the /work-around/.

We already have this generic constraint `create default_create end` in
class WEIGHTED_PATH. That's why I thought it was OK to have it in class
WALK as well if we make it generic.

Jimmy Johnson

unread,
Dec 22, 2021, 12:58:13 PM12/22/21
to Eiffel Users
On Tuesday, December 21, 2021 at 7:56:44 AM UTC-7 lrix wrote:
Also note: I further modified the WEIGHTED_PATH class with more C Generics, which seemed to make better sense given the overall design choices I am making.

Larry,
Could you expand on this.  Why does it make better sense?  Was anchoring to the one feature, which will be redefined, not correct?  I think your code below is easier to read, but with that code, if I redefine `recomputed_cost' to be a descendant of C, then `my_cost' and `set_my_cost' will not follow the redefinition.
jjj

lrix

unread,
Dec 22, 2021, 1:25:48 PM12/22/21
to Eiffel Users
Hi Jimmy!

RE: trading Generics for type anchors—I think both ways is getting to the same goal, but we are changing how and language (and generated compiler code) mechanism is taking us there. In the case of a type anchor, we were anchoring on the type of a single feature. That feature could have been (in turn) anchored to a Generic Parameter.

In my modification, I chose the Generic Parameter as my mechanism because it provides what I think is an easier way for a future programmer to specify the type. In the type anchor scheme, the programmer must not only inherit, but also redefine the feature and provide it a new type on the anchor. The user could get this wrong. Moreover, the compiler will not complain if the type of the anchor is left unchanged.

The easier way of the Generic Parameter means several good outcomes. First—I get to easily specify what the type is by just making the declaration in the inheritance clause (instead of inheritance and redefinition). Second—the compiler helps me to remember to do this so I don't forget because through inheritance the compiler will demand the type specification. Because my descendants will always need to be a downward child of NUMERIC (or retain NUMERIC), I am very clear in communicating to a later version of me or to another programmer what I intend in my design because of the Generic.

You bring to mind an excellent point which I have never fully explored to understand design choices where one chooses either Generic Parameters, type anchors, or perhaps even both. I think this is an excellent side-bar point you have brought up! 

lrix

unread,
Dec 22, 2021, 1:26:58 PM12/22/21
to Eiffel Users
>  but with that code, if I redefine `recomputed_cost' to be a descendant of C, then `my_cost' and `set_my_cost' will not follow the redefinition.

They will if they all are type referenced to the Generic C, yes?

Jimmy Johnson

unread,
Dec 22, 2021, 6:15:49 PM12/22/21
to Eiffel Users
no, if I only redefine `recomputed_cost' but not change the generic they will still conform to C but not the same as the redefined feature.

Jimmy Johnson

unread,
Dec 22, 2021, 9:02:06 PM12/22/21
to Eiffel Users
Maybe I should describe the larger library from which this example was distilled.  I want to make generic containers that model a graph:
     GRAPH - a collection of node and edges (e.g. a map)
     NODE - a nexus in the graph (e.g. a city)
     EDGE - a connection between two nodes (e.g. a street)

These classes are fully implemented; there was no need to have any deferred features.  I'm not sure the benefit of using these classes directly, but that is how they fell out.

The features that relate nodes, edges, and graphs are anchored.  For example, in EDGE:

     node_from: like node_anchor
     node_to: like node anchor
     connect (a_node_from, a_node_to: like node_anchor)

and in NODE:

     children: JJ_SORTABLE_SET [like node_anchor]
     edges: JJ_SORTABLE_SET [like edge_anchor]

and in GRAPH:

     nodes: like node_anchor
     edges: like edge_anchor
     connect_nodes (a_node, a_other_node: like node_anchor)

The anchor features follow the same pattern.  From GRAPH:

        node_anchor: NODE
                        -- Anchor for features using nodes.
                        -- Not to be called; just used to anchor types.
                        -- Declared as a feature to avoid adding an attribute.
                require
                        not_callable: False
                do
                        check
                                do_not_call: False then
                                        -- because gives no info; simply used as anchor.
                        end
                end
        edge_anchor: EDGE
                        -- Anchor for features using nodes.
                        -- Not to be called; just used to anchor types.
                        -- Declared as a feature to avoid adding an attribute.
                require
                        not_callable: False
                do
                        check
                                do_not_call: False then
                                        -- because gives no info; simply used as anchor.
                        end
                end
Descendants become easy to build.  For example, class VALUED_NODE [V] (a node containing a value) adds features `value', `set_value', `has_value, some creation features, and redefines `is_less'.  The anchors are redefined as in:
        node_anchor: VALUED_NODE [V] ...   rest as before
        edge_anchor: VALUED_EDGE [V] ...   rest as before

Some definitions:
   
     VALUED_GRAPH [V] - a graph whose nodes contain values (e.g. cities)
     WEIGHTED_GRAPH [C -> NUMERIC, COMPARABLE ...] - graph whose edges contain a cost (other than one) of traversal (e.g. miles)
     LABELED_GRAPH [L] - a graph whose edges have a label (e.g. street names)

Then combinations of these:

     VALUED_WEIGHTED_GRAPH [V, C -> {NUMERIC, COMPARABLE} ...]
     VALUED_LABELED_GRAPH [V, L]
and so on.

Here is the hierarchy for GRAPH:
Screen Shot 2021-12-22 at 4.30.09 PM.png

The hierarchy for NODE, EDGE, PATH (or WALK), and GRAPH_ITERATOR are analogous and the anchors allow for simple covariant redefinitions.

The choice of "valued", "weighted", and "labeled" allowed for containers covering most types of graphs...and the generic type is what the graph models (e.g. cities, streets, milage).  The number of classes could have grown much more bigly if I had followed most of the graph-theory literature, which describes graph types beyond what I have here, such as directed graph, undirected graph, acyclic graph, simple graph, directed-acyclic graph, etc.  (These characteristics are handled with features.)

To traverse a graph I use class GRAPH_ITERATOR and descendants.  As an iterator traverses a graph (depth-first, breadth-first, shortest path, etc.), it builds a PATH, which I call WALK to avoid a name conflict with the base class PATH.  (Maybe someone can tell me how to use renaming to fix this.)

A PATH is a sequence of EDGEs from a start node to an end node.  There is a cost to travel this path.  At the basic, non-generic-container level, the cost is simply the number of edges in the path.  This was simulated in WALK feature `recomputed_cost' where the result was set to 99.

In WEIGHTED_GRAPH [C -> {NUMERIC, COMPARABLE} ...] each edge has a cost associated with traversing that edge (think miles between cities).  A WEIGHTED_PATH [C ...] then has a cost that is the sum of the edge costs.  The example simulated this with `my_cost', `set_my_cost', and the redefined `recomputed_cost' from WEIGHTED_PATH.  (These costs are not necessarily INTEGER values as in the example!  They could be REAL, IMAGINARY, or any other NUMERIC type that implements "+".)

So if you've made it this far, thanks.  I tried to present the full context for this problem.  I hope you see that I am trying to make generic graph containers while avoiding as much as possible a combinatorial explosion of classes.  (I realize I already have a cornucopia of types, but the descendant classes are very simple.  Class VALUED_LABELED_WEIGHTED_GRAPH, for example, simply redefines three anchor features, that's all.)

Again, thanks for reading all this and for you input.  I'm still trying to get my blinders off and digest Larry and Eric's suggestions.
jjj

lrix

unread,
Dec 23, 2021, 8:32:42 AM12/23/21
to Eiffel Users
Jimmy—I did read all that you wrote. It will take some time to digest all of that, but I generally get it. No worries.


Jimmy Johnson

unread,
Dec 23, 2021, 8:49:56 PM12/23/21
to Eiffel Users
Thanks Larry,

I attached a newer version (below) that is more aligned with the original library.  I added EDGE and WEIGHTED_EDGE so that the `cost' can be computed from the number of edges in EDGE and computed from the sum of the edge costs in WEIGHTED_EDGE.  I still don't understand why I can't do this.

The program seg faults on a call to a feature unrelated to `cost' or `recomputed_cost'.  The problem begins during creation of a WEIGHTED_PATH.  Disclaimer:  when stepping with the debugger, the program runs, but execute without stop points and it seg faults.

In `default_create' from WIEGHTED_PATH...so far so good:

Screen Shot 2021-12-23 at 6.16.05 PM.png

Now stepping into `recomputed_cost' and step to the end.  Still good.  I have to create Result, which is allowed because of the create clause in generics.  Result is 0 because `edges' is empty.

Screen Shot 2021-12-23 at 6.21.41 PM.png 

Now Step ONE line only.  The debugger goes to `twin' from REAL_32.  Okay, not sure why?  Is `twin' always called for an assignment from an expanded type?

Screen Shot 2021-12-23 at 6.26.51 PM.png

At this point, things still look okay, but stepping one more line takes us back to `default_create' just after the assignment statement "cost_imp := recomputed_cost".  Look at the value of `cost_imp' !!!  ???
Why can the debugger show a REAL_32 value of "0" above, but now it is a very small number ?

Screen Shot 2021-12-23 at 6.31.44 PM.png

Stepping into `show_path' and into `cost' on the fourth  `put_string' line, we encounter that oddball value in `cost_imp':

Screen Shot 2021-12-23 at 6.40.08 PM.png

Okay.  I expected the program to seg fault here, but it ran to the end.  If I run the program without stop points it seg faults.

I just had an idea that I am off to try, but regardless, I still wonder why this does not work.
thanks,
jjj
seg_fault.zip

lrix

unread,
Dec 24, 2021, 4:49:06 PM12/24/21
to Eiffel Users
Segfaults for me as well, but I do what the IDE says to do ... open the error and read it.

Again—for whatever stupid reason, Google Groups is NOT letting me upload a PNG file! Arrrrrrgggggg!!!!

The segfaulting code is: WEIGHTED_PATH.edge_count where ...

Result := edges.count

and the error message is:

Error on expression : "edges.count"
Could not find attribute value for `upper'

Looking further to see what "upper" says, and ...

Error on expression : "upper"
[VEEN] Error VEEN
Error code: VEEN

Error: unknown identifier.
What to do: make sure that identifier, if needed, is final name of
  feature of class, or local entity or formal argument of routine.

Class: WALK
Feature: edge_count
Identifier: upper
Target type: [attached like Current] attached WALK
Line: 1
  ->note
    description: "[


So—the segmentation fault is that upper does not have an object--void target call/reference.

Does that information help you?

lrix

unread,
Dec 24, 2021, 5:13:42 PM12/24/21
to Eiffel Users
Okay—so, I found a really nasty problem.

When you create type anchors, always make them detachable! Never use features that must be created (non-void).

The reason you're getting a segfault is that your code is reaching out to an uninitialized feature (edge_anchor) and trying get a type reference that is not there at the time of the call.

lrix

unread,
Dec 24, 2021, 5:33:33 PM12/24/21
to Eiffel Users
CONFIRMED!

ISSUE: Using an attached feature as a type anchor.

SOLUTION: NEVER do this! Always use a detachable as a type anchor feature.

EXAMPLE:

- In WALK, the edge_anchor is now: edge_anchor: detachable EDGE
- Also in WALK, the default_create now has two ensure then contracts:

                ensure then
                        has_edges: attached edges
                        edges_type: attached {LINKED_LIST [attached like edge_anchor]} edges

- Also in WALK, edges is just:

        edges: LINKED_LIST [attached like edge_anchor]

- Also in Walk, extend is now:

        extend (a_edge: attached like edge_anchor)

- NOW—in WEIGHTED_PATH, edge_anchor  is simply: 

        edge_anchor: detachable WEIGHTED_EDGE [C]

Note that I removed all the unnecessary code having to do with not running and so on. It's not needed.

Also note--if you want something that ensures edge_anchor  is not accessed, then set it as an attribute with a ensure contract, such that:

         edge_anchor: detachable WEIGHTED_EDGE [C]
                        -- Anchor for features using edges.

                        -- Not to be called; just used to anchor types.
                        -- Declared as a feature to avoid adding an attribute.
                attribute
                        do_nothing
                ensure then
                        do_not_call: False
                end

Of course, you can put this on the feature in WALK instead and it will carry to inherited and redefinitions as well.

MORAL OF THE STORY: Simply do not create type anchors that are anything other than detachable. If they are there for a non-useable type-reference, then so be it. Otherwise, before you access the type anchoring feature of a non-void target, you will need to do a creation of that target feature.

FINALLY--I run this code successfully now with no segfault.

Jimmy Johnson

unread,
Dec 26, 2021, 12:10:14 PM12/26/21
to Eiffel Users
On Friday, December 24, 2021 at 2:49:06 PM UTC-7 lrix wrote:
Segfaults for me as well, but I do what the IDE says to do ... open the error and read it.
Looking further to see what "upper" says, and ...

Where do you "open" this.
 
 
Error on expression : "upper"
[VEEN] Error VEEN
Error code: VEEN

Error: unknown identifier.
What to do: make sure that identifier, if needed, is final name of
  feature of class, or local entity or formal argument of routine.

Class: WALK
Feature: edge_count
Identifier: upper
Target type: [attached like Current] attached WALK
Line: 1
  ->note
    description: "[


So—the segmentation fault is that upper does not have an object--void target call/reference.

This message looks like a compiler error, not the seg fault.   ??


 

Jimmy Johnson

unread,
Dec 26, 2021, 12:12:38 PM12/26/21
to Eiffel Users
When you create type anchors, always make them detachable! Never use features that must be created (non-void).

What do you mean by "create type anchors"?  I thought I never call the `xxx_anchor' features at all. 

The reason you're getting a segfault is that your code is reaching out to an uninitialized feature (edge_anchor) and trying get a type reference that is not there at the time of the call.

I still don't understand how/when the anchor feature is getting called.  It should only be used for type declarations.
 

Jimmy Johnson

unread,
Dec 26, 2021, 12:36:09 PM12/26/21
to Eiffel Users
Larry, thanks for digging into this.  I'm still digesting what you wrote, but here are my off-the-cuff thoughts.
 
EXAMPLE:

- In WALK, the edge_anchor is now: edge_anchor: detachable EDGE
- Also in WALK, the default_create now has two ensure then contracts:
                ensure then
                        has_edges: attached edges
                        edges_type: attached {LINKED_LIST [attached like edge_anchor]} edges
- Also in WALK, edges is just:
        edges: LINKED_LIST [attached like edge_anchor]
- Also in Walk, extend is now:
        extend (a_edge: attached like edge_anchor)
- NOW—in WEIGHTED_PATH, edge_anchor  is simply: 
        edge_anchor: detachable WEIGHTED_EDGE [C]

Now I have to explicitly say "attached" in every declaration?  Seems like a lot of typing.  Since the anchors never get called anyway, I don't understand the necessity for this.

Also note--if you want something that ensures edge_anchor  is not accessed, then set it as an attribute with a ensure contract, such that:

         edge_anchor: detachable WEIGHTED_EDGE [C]
                        -- Anchor for features using edges.
                        -- Not to be called; just used to anchor types.
                        -- Declared as a feature to avoid adding an attribute.
                attribute
                        do_nothing
                ensure then
                        do_not_call: False
                end

But this adds an attribute to the class, even if Void, where a feature does not add an attribute.  I used non-callable (I thought) features to prevent adding an attribute to the object.  
 
Of course, you can put this on the feature in WALK instead and it will carry to inherited and redefinitions as well.

MORAL OF THE STORY: Simply do not create type anchors that are anything other than detachable. If they are there for a non-useable type-reference, then so be it. Otherwise, before you access the type anchoring feature of a non-void target, you will need to do a creation of that target feature.

Again.  I don't see where I an "creating" any of the anchors.
 
 
FINALLY--I run this code successfully now with no segfault.

Okay, I'm not convinced, but I am going to try your suggestion and see what I can get.  I still think it has something to do with declaring `recomputed_cost' as NUMERIC and then redefining to be generic type C.
Thanks again.
jjj 

Jimmy Johnson

unread,
Dec 26, 2021, 1:57:52 PM12/26/21
to Eiffel Users
Okay, this is an an expanded type (or maybe basic type) versus reference type problem.  All I did was change the actual generic type in the declaration of `real_path' in the APPLICATION class from:
     real_path: weighted_path [REAL]
                -- Path containing egdes that have {REAL} `cost'
to:
     real_path: weighted_path [REAL_REF]
                -- Path containing egdes that have {REAL_REF} `cost'

It works fine now, but who wants to the the xx_REF types?  Not me.
Year ago, wasn't there a problem with expanded (or mixing expanded with reference types) in ARRAYS?

So, now how do I fix this problem and retain the ability to use expanded (or basic) types.
jjj


Ulrich Windl

unread,
Dec 27, 2021, 4:41:10 AM12/27/21
to eiffel...@googlegroups.com
Hi!

A short question: Does Eiffel Studio help whan you are wondering whether there
exists a class that provides "comparable numeric"?
How would one query (excluding queries by class name)?

Regards,
Ulrich

>>> Jimmy Johnson <eiffe...@gmail.com> schrieb am 17.12.2021 um 19:26 in
Nachricht <4c06e336-2fb7-4bd1...@googlegroups.com>:
> Larry,
> Comments are greatly appreciated.
>
> On Friday, December 17, 2021 at 5:08:31 AM UTC-7 lrix wrote:
>
>> This appears to be the case with this code. Generics mixed with more
>> abstract types like NUMERIC was a nearly immediate *code smell* to me.
>> So, the quickest way to test that theory was to change from NUMERIC to
>> INTEGER and see if it compiled. It did. So, the next step was to run the
>> program and see if the segfault persisted. It did not.
>>
>
> Perhaps it's poorly designed, but...the graph classes from which this
> example are derived are generic containers. If I select INTEGER as the
> type then a user can never have edges/paths that have REAL values for the
> cost.
>
>
>> Moral of the story—you did the right thing by reaching out. I also find
>> that I can get horse blinders on myself and it takes another person to spot

>> my error or give me new ideas and approaches. My accounting professor in
>> school called it *Accountants Disease*. When one looks at a column of
>> numbers and cannot see the error in their addition any longer. :-)
>>
>
> In the flying word its "target fixation"-- I keep looking at one thing when

> the error is somewhere else.
>
> I agree, and that is why this list is so great--having someone else look at

> it.
> jjj
>
>
> --
> 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.
> To view this discussion on the web visit
>
https://groups.google.com/d/msgid/eiffel-users/4c06e336-2fb7-4bd1-b289-91a5cf

> 62d946n%40googlegroups.com.



Ulrich Windl

unread,
Dec 27, 2021, 5:46:11 AM12/27/21
to eiffel...@googlegroups.com
>>> Eric Bezault <er...@gobosoft.com> schrieb am 22.12.2021 um 00:00 in
Nachricht
<6ad58e9c-672a-7ced...@gobosoft.com>:
> On 21/12/2021 23:25, lrix wrote:
>> ALSO—with regard to a possible compiler bug, I wonder if the matter
>> could exist deeper—that is—could it be a flaw or ambiguity in the
>> language grammar itself?
>
> I cannot see anything wrong with the language itself here.
> Bertrand, Alexander, any thoughts on that?
>
> The fact that it works fine with the Gobo Eiffel compiler
> makes me think that it is more likely to be a bug in the
> EiffelStudio compiler than a flaw in the language. But
> I may be wrong.

Maybe a better analysis of the problem could be helpful.
Recently I learned that there is some gcc bug with casting and unaligned data.
Maybe that applies, maybe not.

Regards,
Ulrich

>
> --
> Eric Bezault
> mailto:er...@gobosoft.com
> http://www.gobosoft.com
>
> --
> 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.
> To view this discussion on the web visit
>
https://groups.google.com/d/msgid/eiffel-users/6ad58e9c-672a-7ced-ccdc-f7dafd

> dc0a06%40gobosoft.com.



Eric Bezault

unread,
Dec 27, 2021, 6:08:08 AM12/27/21
to eiffel...@googlegroups.com
On 27/12/2021 11:46, Ulrich Windl wrote:
>>>> Eric Bezault <er...@gobosoft.com> schrieb am 22.12.2021 um 00:00 in
>> The fact that it works fine with the Gobo Eiffel compiler
>> makes me think that it is more likely to be a bug in the
>> EiffelStudio compiler than a flaw in the language. But
>> I may be wrong.
>
> Maybe a better analysis of the problem could be helpful.

As I already explained last week, compiling from EiffelStudio
in finalized mode and looking at the generated C code error shows
that the compiler forgot to promote a reference object to an
expanded object or vice-versa. And Jimmy's experiment replacing
REAL by REAL_REF seems to confirm this observation.

Ulrich Windl

unread,
Dec 27, 2021, 6:49:50 AM12/27/21
to eiffel...@googlegroups.com
>>> Jimmy Johnson <eiffe...@gmail.com> schrieb am 26.12.2021 um 19:57 in
Nachricht <1bf36c46-96a8-4653...@googlegroups.com>:

...
> It works fine now, but who wants to the the xx_REF types? Not me.
> Year ago, wasn't there a problem with expanded (or mixing expanded with
> reference types) in ARRAYS?
...

I wonder: How can you mix reference and expanded types in _one_ array?

Regards,
Ulrich


Ulrich Windl

unread,
Dec 27, 2021, 7:21:35 AM12/27/21
to eiffel...@googlegroups.com
>>> Eric Bezault <er...@gobosoft.com> schrieb am 27.12.2021 um 12:08 in Nachricht
<5c5e6053-b2a4-b13d...@gobosoft.com>:
Sorry, I did not follow the whole thread when writing the response.

Regards,
Ulrich

>
> --
> Eric Bezault
> mailto:er...@gobosoft.com
> http://www.gobosoft.com
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/5c5e6053-b2a4-b13d-b04a-3aeb5b
> 951928%40gobosoft.com.




Jimmy Johnson

unread,
Dec 27, 2021, 2:59:35 PM12/27/21
to Eiffel Users
Yes Eric, I reread your answers and now I understand.  So...what can I do about it?
jjj 

lrix

unread,
Dec 28, 2021, 7:39:36 AM12/28/21
to Eiffel Users
On Sunday, December 26, 2021 at 12:36:09 PM UTC-5 eiffe...@gmail.com wrote:
Larry, thanks for digging into this.  I'm still digesting what you wrote, but here are my off-the-cuff thoughts.

You're welcome! :-)
 

Now I have to explicitly say "attached" in every declaration?  Seems like a lot of typing.  Since the anchors never get called anyway, I don't understand the necessity for this.

I know you are not kidding, but are you kidding? :-)


But this adds an attribute to the class, even if Void, where a feature does not add an attribute.  I used non-callable (I thought) features to prevent adding an attribute to the object.  
...
Again.  I don't see where I an "creating" any of the anchors.

You are not "creating" any anchors as features at all (i.e. for calling by a caller). They are type references. They only need to be there for the compiler at compile-time. Because of dead-code removal, I am not even sure if they exist in the finalized EXE at all. Now, as a type reference they might exist in the EXE, but (again) they are just references for those features that require a type reference. They perform no other useful function in your program.

Yes—you do need to type attached like for each instance where you actually utilize the type reference (anchor). This is not unreasonable and it is not a lot of typing. As Bertrand wrote years ago—there is no tax on keystrokes. But—if it makes you feel better—if the point in code where you need to reference the type anchor reference does not need to be attached (non-void), then you do not need to type the keyword attached. Why? Because when you write like that liking-reference will follow whatever attachment scheme has been specified in the thing being referenced. If it is declared as attached, then the like will also be attached. If detachable, then the like will be detachable. If you want the referencing item to be attached and the referenced item is detachable, then you need to explicitly specify attached.
 
Okay, I'm not convinced, but I am going to try your suggestion and see what I can get.  I still think it has something to do with declaring `recomputed_cost' as NUMERIC and then redefining to be generic type C.
Thanks again.
jjj 

Remember—the way you had the code, you were creating a feature that was non-void (attached) and (therefore) you were responsible for creating it at creation time in a creation procedure—or—making it as a self-creating attribute. The segfault error was arising because when your code arrived at the point where it was referencing your type anchor, the object was not created and was therefore NULL (Void). Because there was no object to reference and fetch its type, the program failed with a call on void target segfault. Had the object actually been created, there would have been an object to reference and (therefore) a type reference to successfully fetch and utilize in a like

Moreover—the reason your program did not fail in the debugger as you stepped through is because (I think) the debugger provides extra data about the program for debugging purposes as it executes. That data is not present in the W-Code or F-Code version of an EXE—only in the Debugger-Code version. So, in either W-Code or F-Code EXE, the object was not there, so the Void-target call failed as a segfault.

Again—the way out of that trap is two-fold. Either ...

1. Ensure that the object is created BEFORE it is referenced.
2. Ensure that the type anchor is detachable and that if the referencing like is attached then ensure you use the attached keyword in that reference.

Finally—if you use the format of declaring type references as detachable then you do not have to worry about them being called as such. Why? because there is nothing there to call, only to reference (which is their purpose, yes?). This means you do not need to put in code as a guard dog over the type reference feature. As a programmer, even the IDE + Compiler will stop you from calling the feature as though it were callable (executable). It is not. It is a void-object reference only. Nothing to see here. Move along.

:-)

Larry

lrix

unread,
Dec 28, 2021, 7:48:19 AM12/28/21
to Eiffel Users

But this adds an attribute to the class, even if Void, where a feature does not add an attribute.  I used non-callable (I thought) features to prevent adding an attribute to the object.  
...
Again.  I don't see where I an "creating" any of the anchors.


One other thing to say about this—I generally place such type anchor references in "feature {NONE} -- Implementation: Anchors" feature clauses so that they are not accessible or reference-able by external clients of a class. All of the wonderful rules about feature exporting apply, so you can export features as you see fit. However, I always start by using the above-mentioned export-feature-clause structure so that the type reference is only accessible by the class itself.

Finally—if you want to ensure that the detachable type anchor feature never actually gets attached then add a class invariant specifying this fact or reality (i.e. you want your program to break if a Client ever actually tries to attach an object to your type anchor reference).

Jimmy Johnson

unread,
Dec 28, 2021, 10:27:32 PM12/28/21
to Eiffel Users
On Tuesday, December 28, 2021 at 5:48:19 AM UTC-7 lrix wrote:

But this adds an attribute to the class, even if Void, where a feature does not add an attribute.  I used non-callable (I thought) features to prevent adding an attribute to the object.  
...
Again.  I don't see where I an "creating" any of the anchors.


One other thing to say about this—I generally place such type anchor references in "feature {NONE} -- Implementation: Anchors" feature clauses so that they are not accessible or reference-
 
I agree, and i thought I did not export the xxx_anchor features.  If I did in the example, it was a mistake.
 
Finally—if you want to ensure that the detachable type anchor feature never actually gets attached then add a class invariant specifying this fact or reality (i.e. you want your program to break if a

I believe this structure for my anchors prevents calls:
                         check
                                do_not_call: False then
                                        -- Because give no info; simply used as anchor.
                        end
                end
The "False then" is not removed even if all contracts are off.  OTH, adding this check as an invariant works only if invariant checking is on. 

Client ever actually tries to attach an object to your type anchor reference).

I use features so "attaching an object" is not allowed. 


Jimmy Johnson

unread,
Dec 28, 2021, 10:52:12 PM12/28/21
to Eiffel Users
Now I have to explicitly say "attached" in every declaration?  Seems like a lot of typing.  Since the anchors never get called anyway, I don't understand the necessity for this.

I know you are not kidding, but are you kidding? :-)

A little.  I don't mind typing and I agree with your quote from Bertrand, "there is no tax on keystrokes".  (I knew better than to write that.)  What I mean to say is, it is too much typing when it is not necessary.
 
But this adds an attribute to the class, even if Void, where a feature does not add an attribute.  I used non-callable (I thought) features to prevent adding an attribute to the object.  
...

I should have said "function" not "feature" in the above line.
 
Again.  I don't see where I an "creating" any of the anchors.

You are not "creating" any anchors as features at all (i.e. for calling by a caller). They are type references. They only need to be there for the compiler at compile-time. Because of dead-code removal, I am not even sure if they exist in the finalized EXE at all. Now, as a type reference they might exist in the EXE, but (again) they are just references for those features that require a type reference. They perform no other useful function in your program.

Larry, I was referring to the example you sent where you declared the anchors as attributes.  Even if never call, they add a field to the object, even if it is Void.  Think what this does in the presence of persistence.
 
Yes—you do need to type attached like for each instance where you actually utilize the type reference (anchor). This is not unreasonable and it is not a lot of typing. As Bertrand wrote years ago—there is no tax on keystrokes. But—if it makes you feel better—if the point in code where you need to reference the type anchor reference does not need to be attached (non-void), then you do not need to type the keyword attached. Why? Because when you write like that liking-reference

But with Void safety I want the default all declarations to be attached, unless detached is required for a specific reason.
 
Remember—the way you had the code, you were creating a feature that was non-void (attached) and (therefore) you were responsible for creating it at creation time in a creation procedure—or—making it as a self-creating attribute. The segfault error was arising because when your code arrived at the point where it was referencing your type anchor, the object was not created and was

I don't think anywhere do I reference (I think you mean call) a type anchor.  As you say the anchors are there for the compiler to handle.  In your context, there is no object attached to/as a type anchor.  I don't really understand what you mean.
 
therefore NULL (Void). Because there was no object to reference and fetch its type, the program failed with a call on void target segfault. Had the object actually been created, there would have been an object to reference and (therefore) a type reference to successfully fetch and utilize in a like

I think Eric is right.  The program fails because of the relationships in the program between reference and expanded type declarations.
 
Moreover—the reason your program did not fail in the debugger as you stepped through is because (I think) the debugger provides extra data about the program for debugging purposes as it executes. That data is not present in the W-Code or F-Code version of an EXE—only in the Debugger-Code version. So, in either W-Code or F-Code EXE, the object was not there, so the Void-target call failed as a segfault.

Again, there is no call on Void target.  It crashes because of an improper reference to memory.  It worked in the debugger, likely because there just happened to be correctly formatted data at the referenced memory location.  Think about referencing a non-initialized pointer in C; sometimes it actually works.
 
Again—the way out of that trap is two-fold. Either ...

1. Ensure that the object is created BEFORE it is referenced.
2. Ensure that the type anchor is detachable and that if the referencing like is attached then ensure you use the attached keyword in that reference.

Finally—if you use the format of declaring type references as detachable then you do not have to worry about them being called as such. Why? because there is nothing there to call, only to reference (which is their purpose, yes?). This means you do not need to put in code as a guard dog over the type reference feature. As a programmer, even the IDE + Compiler will stop you from calling the feature as though it were callable (executable). It is not. It is a void-object reference only. Nothing to see here. Move along.

I don't understand.  I do have to worry about features being called.  You can always erroneously call a feature even if it is Void.  That is why Eiffel has Void safety; to tell you that you messed up.  I think you and I (mostly my fault) are confusing each other by using "feature" instead of "attribute" and "function".  I declare the anchor features as functions:
1)  to not add an attribute to the objects
2)  to prevent attempting to assign a value to it
I use the check statement with "False then" to:
1)  fail if it is called
2)  keep the check in the finalized code (I could be wrong about this.)

Again, though, I think Eric has pin downed the problem.  I eagerly await any advice from Eiffel Software.
jjj
 

lrix

unread,
Dec 29, 2021, 6:39:07 PM12/29/21
to Eiffel Users
Jimmy—do you still have my phone number? Perhaps a voice call would help because we're way far in the weeds and it seems obvious that something is being misunderstood by one or both of us. I just want to ensure I understand you clearly and I don't think I am.

SVHarvey (Optus)

unread,
Dec 29, 2021, 9:02:31 PM12/29/21
to eiffel...@googlegroups.com
My version of the code works for generic parameter values of INTEGER, DECIMAL, REAL, DOUBLE, when I …

define WALK by …
class
WALK [C -> {NUMERIC} create default_create end]
modify its creation to …
default_create
-- Initialize `Current' with costing function `default_cost'.
do
create edges.make
create cost_imp
ensure then
is_clean: is_clean
end
modify recomputed_cost from …
recomputed_cost: C
-- Calculate the `cost', memorising the result
-- in `cost_imp'.
do
Result := edges.count
cost_imp := Result
set_clean
ensure
is_clean: is_clean
end
(because it was generating conformance errors) to …
recomputed_cost: C
-- Calculate the `cost', memorising the result
-- in `cost_imp'.
local
l_c, l_zero, l_one: C
do
create l_c
l_zero := l_c.zero
l_one := l_c.one
Result := l_zero
⟳ e: edges ¦ Result := Result + l_one ⟲
cost_imp := Result
set_clean
ensure
is_clean: is_clean
end
and replace all “like cost_anchor” with “C"


and replace class WEIGHTED_WALK by …
class
WEIGHTED_WALK [C -> {NUMERIC, COMPARABLE rename default_create as default_commparable end} create default_create end]

inherit
WALK [C]
redefine
recomputed_cost
end

create
default_create

feature {NONE} -- Implementation

recomputed_cost: C
-- Calculate the `cost', memorising the result
-- in `cost_imp'.
do
Create Result
⟳ e: edges ¦ Result := Result + e.cost ⟲
cost_imp := Result
set_clean
end

end


where classes EDGE and WEIGHTED_EDGE are …

class
EDGE [C -> {NUMERIC} create default_create end]

feature -- Access

cost: C
-- Cost for traversing `Current'.
do
Result := (create {C}).one
end

end



class
WEIGHTED_EDGE [C -> {NUMERIC, COMPARABLE rename default_create as default_commparable end} create default_create end]

inherit
EDGE [C]
redefine
default_create,
cost
end

create
default_create
,make

feature {NONE} -- Initialization

default_create
-- Initialize `Current' with a `cost' of one.
local
l_cost: like cost
do
create l_cost
cost := l_cost.one
end

make (a_cost: C)
-- Initialize `Current' with cost set as `a_cost' .
do
cost := a_cost
end

feature -- Access

cost: C
-- Cost of traversing `Current'.
end

Cheers,
Simon
On 30 Dec 2021, at 10:39, lrix <lr...@jinny.com> wrote:

Jimmy—do you still have my phone number? Perhaps a voice call would help because we're way far in the weeds and it seems obvious that something is being misunderstood by one or both of us. I just want to ensure I understand you clearly and I don't think I am.


--
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.

Jimmy Johnson

unread,
Dec 29, 2021, 9:46:44 PM12/29/21
to Eiffel Users
How does this handle a graph that does not have weighted edges?  That is, it has edges that have no generic; they simply connect two nodes?
jjj

Ulrich Windl

unread,
Jan 3, 2022, 3:45:47 AM1/3/22
to eiffel...@googlegroups.com
>>> "SVHarvey (Optus)" <svha...@optusnet.com.au> schrieb am 30.12.2021 um 03:02 in
Nachricht <E091B230-1F67-45BF...@optusnet.com.au>:
...
> class
> WEIGHTED_WALK [C -> {NUMERIC, COMPARABLE rename default_create as
> default_commparable end} create default_create end]
>
...

I wonder: Is it considered to be good style to define a "helper class" NUMERIC_COMPARABLE and use that instead, or is it considered bad style?
Specifically I wonder what to do if you need the same type again.
Also in my far distant knowledge of Eiffel I thought "every type is a class and every class is a type" (or similar).
How do such unnamed types fit in here?

Regards,
Ulrich


Eric Bezault

unread,
Jan 3, 2022, 3:56:00 AM1/3/22
to eiffel...@googlegroups.com
On 03/01/2022 9:45, Ulrich Windl wrote:
>>>> "SVHarvey (Optus)" <svha...@optusnet.com.au> schrieb am 30.12.2021 um 03:02 in
> Nachricht <E091B230-1F67-45BF...@optusnet.com.au>:
> ...
>> class
>> WEIGHTED_WALK [C -> {NUMERIC, COMPARABLE rename default_create as
>> default_commparable end} create default_create end]
>>
> ...
>
> I wonder: Is it considered to be good style to define a "helper class" NUMERIC_COMPARABLE and use that instead, or is it considered bad style?

The problem is that third-party classes (such as INTEGER) which inherit
from COMPARABLE and NUMERIC don't inherit from your new class
NUMERIC_COMPARABLE.

And the combination of classes may be huge: NUMERIC_HASHABLE,
COMPARABLE_HASHABLE, NUMERIC_COMPARABLE_HASHABLE, NUMERIC_DISPOSABLE,
COMPARABLE_DISPOSABLE, HASHABLE_DISPOSABLE, NUMERIC_HASHABLE_DISPOSABLE,
NUMERIC_COMPARABLE_DISPOSABLE, ...

Ulrich Windl

unread,
Jan 3, 2022, 5:11:23 AM1/3/22
to eiffel...@googlegroups.com
>>> Eric Bezault <er...@gobosoft.com> schrieb am 03.01.2022 um 09:55 in Nachricht
<992ee5b8-a9c3-c791...@gobosoft.com>:
> On 03/01/2022 9:45, Ulrich Windl wrote:
>>>>> "SVHarvey (Optus)" <svha...@optusnet.com.au> schrieb am 30.12.2021 um 03:02
> in
>> Nachricht <E091B230-1F67-45BF...@optusnet.com.au>:
>> ...
>>> class
>>> WEIGHTED_WALK [C -> {NUMERIC, COMPARABLE rename default_create as
>>> default_commparable end} create default_create end]
>>>
>> ...
>>
>> I wonder: Is it considered to be good style to define a "helper class"
> NUMERIC_COMPARABLE and use that instead, or is it considered bad style?
>
> The problem is that third-party classes (such as INTEGER) which inherit
> from COMPARABLE and NUMERIC don't inherit from your new class
> NUMERIC_COMPARABLE.

Hi!

Trying to understand what section 8.12 of the ECMA document says abaout it, I'm just confused (that is very hard to read, i.e. understand):
Asuming Formal_generic_list {NUMERIC, COMPARABLE} requires conformance to NUMERIC _and_ COMPARABLE I don't see the difference;
if it would mean NUMERIC _or_ COMPARABLE I don't see the sense in it.
Sorry If I sound stupid.

Regards,
Ulrich

>
> And the combination of classes may be huge: NUMERIC_HASHABLE,
> COMPARABLE_HASHABLE, NUMERIC_COMPARABLE_HASHABLE, NUMERIC_DISPOSABLE,
> COMPARABLE_DISPOSABLE, HASHABLE_DISPOSABLE, NUMERIC_HASHABLE_DISPOSABLE,
> NUMERIC_COMPARABLE_DISPOSABLE, ...
>
> --
> Eric Bezault
> mailto:er...@gobosoft.com
> http://www.gobosoft.com
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/992ee5b8-a9c3-c791-2a0f-e86053
> e7f8ef%40gobosoft.com.




Eric Bezault

unread,
Jan 3, 2022, 5:18:28 AM1/3/22
to eiffel...@googlegroups.com
On 03/01/2022 11:11, Ulrich Windl wrote:> Trying to understand what
section 8.12 of the ECMA document says abaout it, I'm just confused
(that is very hard to read, i.e. understand):> Asuming
Formal_generic_list {NUMERIC, COMPARABLE} requires conformance to
NUMERIC _and_ COMPARABLE I don't see the difference;

The difference in what?

INTEGER conforms to NUMERIC and COMPARABLE.
If you add a class NUMERIC_COMPARABLE, then all descendants of this
class will conform to NUMERIC and COMPARABLE.
But INTEGER does not conform to NUMERIC_COMPARABLE.

Ulrich Windl

unread,
Jan 3, 2022, 7:52:57 AM1/3/22
to eiffel...@googlegroups.com
>>> Eric Bezault <er...@gobosoft.com> schrieb am 03.01.2022 um 11:18 in Nachricht
<3bda639d-0eff-98e8...@gobosoft.com>:
> On 03/01/2022 11:11, Ulrich Windl wrote:> Trying to understand what
> section 8.12 of the ECMA document says abaout it, I'm just confused
> (that is very hard to read, i.e. understand):> Asuming
> Formal_generic_list {NUMERIC, COMPARABLE} requires conformance to
> NUMERIC _and_ COMPARABLE I don't see the difference;
>
> The difference in what?
>
> INTEGER conforms to NUMERIC and COMPARABLE.
> If you add a class NUMERIC_COMPARABLE, then all descendants of this
> class will conform to NUMERIC and COMPARABLE.
> But INTEGER does not conform to NUMERIC_COMPARABLE.

Ah, I see: It should have been foreseen that NUMERIC_COMPARABLE is not that rare.
Thanks for explaining, now it's clear!

>
> --
> Eric Bezault
> mailto:er...@gobosoft.com
> http://www.gobosoft.com
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/3bda639d-0eff-98e8-8b90-6a3572
> a92e64%40gobosoft.com.




Finnian Reilly

unread,
Jan 8, 2022, 6:38:13 PM1/8/22
to Eiffel Users

class
EDGE [C -> {NUMERIC} create default_create end]

feature -- Access

cost: C
-- Cost for traversing `Current'.
do
Result := (create {C}).one
end

end

Why use numeric reference types when you can use expanded types? This code works just as well and is faster.
class
        EDGE [C -> NUMERIC]


feature -- Access

        cost: C
                        -- Cost for traversing `Current'.
                local
                        n: C
                do
                        Result := n.one
                end

end

Jimmy Johnson

unread,
Jan 10, 2022, 4:07:21 PM1/10/22
to Eiffel Users
two reasons:
1)  I don't want EDGE (at the top of hierarchy) to be generic.
2)  Making `cost' type NUMERIC (as opposed to generic C) does not work.  (See rest of this thread.)
jjj

Jimmy Johnson

unread,
Jan 14, 2022, 2:49:55 PM1/14/22
to Eiffel Users
I hate to keep hitting this horse, but I'm stuck.  I don't think this design is unreasonable, and I'm hoping someone from Eiffel Software can chime in.

This new attached zip file differs from the originally posted classes.  PATH now defines `cost' as a NUMERIC, and WEIGHTED_PATH [C -> NUMERIC...] redefines `cost' as type C.  This works just fine.  
The problem is demonstrated in the new classes PATH_WITH_RECOMPUTE and WEIGHTED_PATH_WITH_RECOMPUTE [C -> NUMERIC...].  As in the original post, these classes memoize `cost' and anchor to `recomputed_cost'.  This code will seg fault.  

Thanks again,
jjj
seg_fault.zip

lrix

unread,
Jan 15, 2022, 7:00:13 AM1/15/22
to Eiffel Users
Jimmy,

Again—make your anchors detachable and your references attached like and the whole thing just works.

lrix

unread,
Jan 15, 2022, 7:04:50 AM1/15/22
to Eiffel Users
Jimmy.

Also—I changed nothing about your design,. That is your choice to make. All I did was comment out the require ... do ... end on your type-anchors (edge_anchor) and make them detachable. I then located the references (a pair of arguments) and made them attached like instead of just like.

The problem is always the same. You get a segfault because at run-time the code tries to type-ref a Void feature. By making the type-anchoring feature detachable and using the attached like on the references, you get what you want—working code. 

lrix

unread,
Jan 15, 2022, 7:07:07 AM1/15/22
to Eiffel Users
feature -- Basic operations


        extend (a_edge: attached like edge_anchor)
                        -- Add `a_edge' to Current
                do
                        edges.extend (a_edge)
                end

feature {NONE} -- Implementation


        edges: LINKED_LIST [attached like edge_anchor]
                        -- The edges traversed in this path

feature {NONE} -- Implementation

        edge_anchor: detachable EDGE

                        -- Anchor for features using edges.
                       
-- Not to be called; just used to anchor types.

                        -- Declared as a feature to avoid adding an attribute.
--                require
--                        not_callable: False
--                do
--                        check
--                                do_not_call: False then
--                                        -- Because give no info; simply used as anchor.
--                        end
--                end

r...@amalasoft.com

unread,
Jan 15, 2022, 8:24:38 AM1/15/22
to eiffel...@googlegroups.com
Hi Larry
That's a good way to get it to work but I worry that there remains an underlying problem.
The 'like' mechanism should be associating a type (i.e. a class), NOT an instance.  The anchor feature is never called, EVER, in the program definition (i.e. the code).  Ass such, it should never be called by another entity i.e. the runtime system).
I worry that the type anchoring, that SHOULD occur at compile time is somehow off (it should not have to look at the anchor feature at runtime), perhaps the victim of dead code removal.
Eiffel has static typing and so this problem should never occur, and yet it does.
That said, it should be permitted to do exactly as you describe.  That method makes the code more explicit, but I think it also makes is unnecessarily wordy.  The anchor feature exists once in the code, but (presumably, else why use an anchor) its type affiliations (instances of 'like') are possibly many.
R
--
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.

lrix

unread,
Jan 15, 2022, 5:03:44 PM1/15/22
to Eiffel Users
LOL—is everyone just missing the point?

  • The very definition of a type anchor is the type and not an attached object. Making detachable signifies that. Giving it a do ... end routine body is silliness because, as you said, nobody is going to CALL it. All they will do is reference it.
  • Even using an attribute ... end to provide a lazy-instance of an object is also a little silly when all one wants is the type, anchored to a feature.
  • Wordy? Seriously? I am falling into the looking glass. Is it seriously difficult to type the word attached or even to read it? We cannot be having this discussion, right?
  • To your credit, I think what you are really griping about here is a nuance in the compiler's static type checking vs run-time object reference behavior.
Thoughts about that last point

I think what you expect is for the compiler to statically use the anchor type definition. HOWEVER—once you make that a non-Void type in a run-time situation, here is what you are left with: You are left with a POLYMORPHIC OBJECT that can be whatever type you declared AND any valid legal polymorphic descendent type. THEREFORE—you MUST have an object for the run-time program to reference through the like in wherever it is being referenced!

Compare that to having a detachable type anchor.

In the detachable version, the type reference will NOT be based on the type of the OBJECT pointed to by the feature. It will simply be as you are expecting—a reference based on the type of the anchor feature declared statically just as you read it in the code.

The ONE nuance will be IF you redefine the type-anchor reference in a descendant class. If you do—NO PROBLEM! The compiler is quite good at understanding your polymorphic construction and changes the expectation in the like reference based on the descendant class anchor reference.

Again—putting a feature that MUST have an attached object means you THROW AWAY the static type reference of the code and change the reference to an OBJECT INSTANCE AT RUN-TIME because of polymorphic assignment capacity on that feature. It doesn't matter if it is ever "called" or not.

lrix

unread,
Jan 15, 2022, 5:17:22 PM1/15/22
to Eiffel Users
On the other hand—if the design is to actually have an EDGE reference that changes type-reference based on a polymorphic object at run-time, then—by all means—create the feature as an attribute and then ensure that it is a part of the creation procedure—OR—is lazy-created as an attribute ... end feature. In this case, you can put an EDGE object or whatever descendant you like, changing it as you go, however you like. You will just need to ensure that at the PRECISE INSTANT that the feature is used as a type reference anchor that the object is of the proper and legal type expected by your referencing code (e.g. argument type reference). This gets very tricky and is HIGHLY PRONE to bugs! You really REALLY don't want to do this. You can! But you don't want to. Better to use something like a Generic Parameter in the type anchor or just redefine it in a descendant where you as a programmer can reason about the type anchor. Nothing like pulling the rug out from under your feet because the object in the type-anchor was misaligned with what you designed the type-reference consumer to expect!

Eric Bezault

unread,
Jan 15, 2022, 6:44:56 PM1/15/22
to eiffel...@googlegroups.com
On 15/01/2022 23:03, lrix wrote:
> I think what you expect is for the compiler to statically use the anchor
> type definition.

And that's what it should do according to the Eiffel standard.

> HOWEVER—once you make that a non-Void type in a
> run-time situation, here is what you are left with: You are left with a
> POLYMORPHIC OBJECT that can be whatever type you declared AND *any*
> *valid legal polymorphic descendent type*. THEREFORE—you *MUST *have an
> *object *for the *run-time program *to reference through the *like* in
> wherever it is being referenced!

This does not make sense to me. Anchored types have nothing to do
with runtime objects. They are used only at compilation time.
That's how it's defined in the standard, that's how it's implemented
in the Gobo Eiffel compiler, and that's how it worked for me with
EifelStudio during years.

I already mentioned in previous messages that the bug in EiffelStudio
is occurring when there is a redefinition of a signature combining
both formal generic parameters and reference vs. expanded types.
The fact that using detachable anchored types seems to work as a
workaround for this bug is just coincidence. For sure it has nothing
to do with having objects at runtime to reference the like because
this is not how anchored types work.

lrix

unread,
Jan 15, 2022, 7:33:37 PM1/15/22
to Eiffel Users
Perhaps it is a bug in the compiler. Perhaps it is.

Jimmy Johnson

unread,
Jan 15, 2022, 10:35:43 PM1/15/22
to Eiffel Users
On Saturday, January 15, 2022 at 6:24:38 AM UTC-7 rfo wrote:
Hi Larry
That's a good way to get it to work but I worry that there remains an underlying problem.
The 'like' mechanism should be associating a type (i.e. a class), NOT an instance.  The anchor feature is never called, EVER, in the program definition (i.e. the code).  Ass such, it should never be called by another entity i.e. the runtime system).
 
Exactly.  It is never called

I worry that the type anchoring, that SHOULD occur at compile time is somehow off (it should not have to look at the anchor feature at runtime), perhaps the victim of dead code removal.

I agree.  Something seems off.  Where is Eiffel Software on this one?
 
Eiffel has static typing and so this problem should never occur, and yet it does.
That said, it should be permitted to do exactly as you describe.  That method makes the code more explicit, but I think it also makes is unnecessarily wordy.  The anchor feature

Yes
 
exists once in the code, but (presumably, else why use an anchor) its type affiliations (instances of 'like') are possibly many.
R

Yes there are MANY affiliations in the original system.
 jjj

Jimmy Johnson

unread,
Jan 15, 2022, 10:46:55 PM1/15/22
to Eiffel Users
On Saturday, January 15, 2022 at 5:04:50 AM UTC-7 lrix wrote:
Jimmy.

Also—I changed nothing about your design,. That is your choice to make. All I did was comment out the require ... do ... end on your type-anchors (edge_anchor) and make them detachable. I then located the references (a pair of arguments) and made them attached like instead of just like.

The problem is always the same. You get a segfault because at run-time the code tries to type-ref a Void feature. By making the type-anchoring feature detachable and using the attached like on the references, you get what you want—working code. 

Okay, I'll try this in the example code.  In the library from which this example is derived there are far to many uses of "like ..._anchor" to make this feasible.
Even if it works, though, it does not address the real problem.  The compiler lets this by, yet it produces a fault.
On the other hand, working code... 

 

Jimmy Johnson

unread,
Jan 15, 2022, 11:03:01 PM1/15/22
to Eiffel Users
On Saturday, January 15, 2022 at 3:03:44 PM UTC-7 lrix wrote:
LOL—is everyone just missing the point?

  • The very definition of a type anchor is the type and not an attached object. Making detachable signifies that. Giving it a do ... end routine body is silliness because, as you said, nobody is going to CALL it. All they will do is reference it.
I disagree.  It is not that silly.  Think of persistence.  Making the anchor features attributes adds additional fields to each object.  Granted, the references are all Void, but a persistence mechanism has to deal with the additional fields.  (For some reason I can't remember the proper Eiffel word analogous to "field".)  Defining these features as functions does not add a field; and, I don't know, but I bet they are optimized out by the compiler.
  • Even using an attribute ... end to provide a lazy-instance of an object is also a little silly when all one wants is the type, anchored to a feature.
  • Wordy? Seriously? I am falling into the looking glass. Is it seriously difficult to type the word attached or even to read it? We cannot be having this discussion, right?
Yes it is difficult when "like ...anchor" permeates many classes of a library.
 
  • To your credit, I think what you are really griping about here is a nuance in the compiler's static type checking vs run-time object reference behavior.
I really don't think this is runtime; my guess is a hole in the compiler.  Does Eiffel Software have any thoughts?
 
Thoughts about that last point

I think what you expect is for the compiler to statically use the anchor type definition. HOWEVER—once you make that a non-Void type in a run-time situation, here is what you are left with: You are left with a POLYMORPHIC OBJECT that can be whatever type you declared AND any valid legal polymorphic descendent type. THEREFORE—you MUST have an object for the run-time program to reference through the like in wherever it is being referenced!

Larry, that sounds wrong.  The anchor is only for the compiler.  "Like" is a very nice Eiffel feature that makes the programmer's life easier.  It has nothing to do with the runtime.  These anchor features are each a FUNCTION that is NEVER called!  (This is also guaranteed at run-time, with the check statement, using "False THEN".)  You keep mixing that up with the runtime.

Compare that to having a detachable type anchor.

In the detachable version, the type reference will NOT be based on the type of the OBJECT pointed to by the feature. It will simply be as you are expecting—a reference based on the type of the anchor feature declared statically just as you read it in the code.

What?  see above.
 
The ONE nuance will be IF you redefine the type-anchor reference in a descendant class. If you do—NO PROBLEM! The compiler is quite good at understanding your polymorphic construction and changes the expectation in the like reference based on the descendant class anchor reference.

Again—putting a feature that MUST have an attached object means you THROW AWAY the static type reference of the code and change the reference to an OBJECT INSTANCE AT RUN-TIME because of polymorphic assignment capacity on that feature. It doesn't matter if it is ever "called" or not.

Sorry, Larry.  I just don't buy this and really don't understand what you are trying to say.  "Like" is a compile-time construct; there is never an instance of any of the anchors, so no "OBJECT INSTANCE AT RUN-TIME" to worry about.
 
I will now try your "solution" in the hope a new idea will fall out of it.  Thanks, and hope I don't sound too harsh; I'm just frustrated.
jjj

Eric Bezault

unread,
Jan 16, 2022, 11:34:24 AM1/16/22
to eiffel...@googlegroups.com
On 16/01/2022 1:33, lrix wrote:
> Perhaps it is a bug in the compiler. Perhaps it is.

This is what I get when using the Gobo Eiffel compiler:

~~~~~~~~~~~~~~~~~~~~~~~~~
PS C:\jjj2> gec --finalize fault_tester.ecf
Degree 6: 0/0/0 0:0:0.018
Degree 5: 0/0/0 0:0:0.125
Degree 4: 0/0/0 0:0:0.031
Degree 3: 0/0/0 0:0:0.047
Degree -2: 0/0/0 0:0:0.023
Degree -3: 0/0/0 0:0:0.047
[...]
Degree -4: 0/0/0 0:0:1.953
Total Time: 0/0/0 0:0:2.249

PS C:\jjj2> .\fault_tester.exe
{PATH}: count = 0 cost = 0
{PATH}: count = 2 cost = 2
{PATH}: count = 2 cost = 2
{WEIGHTED_PATH [REAL_32]}: count = 0 cost = 0
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{PATH_WITH_RECOMPUTE}: count = 0 cost = 0
{WEIGHTED_PATH_WITH_RECOMPUTE [REAL_32]}: count = 2 cost = 7.6
~~~~~~~~~~~~~~~~~~~~~~~~~

And I get a segmentation violation when using EiffelStudio
both in workbench mode:

~~~~~~~~~~~~~~~~~~~~~~~~~
PS C:\jjj2> ec -config fault_tester.ecf -c_compile
Eiffel Compilation Manager
Version 21.11.10.6046 - win64

Degree 6: Examining System
Degree 5: Parsing Classes
Degree 4: Analyzing Inheritance
Degree 3: Checking Types
Degree 2: Generating Byte Code
Freezing System Changes
Degree -1: Generating Code
[...]
C compilation completed

PS C:\jjj2> .\EIFGENs\fault_tester\W_code\fault_tester.exe
{PATH}: count = 0 cost = 0
{PATH}: count = 2 cost = 2
{PATH}: count = 2 cost = 2
{WEIGHTED_PATH [REAL_32]}: count = 0 cost = 0
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{PATH_WITH_RECOMPUTE}: count = 0 cost = 0
{WEIGHTED_PATH_WITH_RECOMPUTE [REAL_32]}:
fault_tester: system execution failed.
Following is the set of recorded exceptions:

-------------------------------------------------------------------------------
Class / Object Routine Nature of exception
Effect
-------------------------------------------------------------------------------
WEIGHTED_PATH_WITH_RECOMPUTE
edge_count @1 Segmentation violation:
<0000021ACCBA9EA8> (From PATH_WITH_RECOMPUTE)
Operating system signal.
Fail
-------------------------------------------------------------------------------
WEIGHTED_PATH_WITH_RECOMPUTE
edge_count @1
<0000021ACCBA9EA8> (From PATH_WITH_RECOMPUTE)
Routine failure.
Fail
-------------------------------------------------------------------------------
APPLICATION show_path_with_recompute @2
<0000021ACCBA7588> Routine failure.
Fail
-------------------------------------------------------------------------------
APPLICATION make @22
<0000021ACCBA7588> Routine failure.
Fail
-------------------------------------------------------------------------------
APPLICATION root's creation
<0000021ACCBA7588> Routine failure.
Exit
-------------------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~

and in finalized mode:

~~~~~~~~~~~~~~~~~~~~~~~~~
PS C:\jjj2> ec -config fault_tester.ecf -c_compile -finalize
Eiffel Compilation Manager
Version 21.11.10.6046 - win64

Degree 6: Examining System
Degree -2: Constructing Polymorphic Table
Removing Unused Code
Degree -3: Generating Optimized Code
System Recompiled.
[...]
C compilation completed

PS C:\jjj2> .\EIFGENs\fault_tester\F_code\fault_tester.exe
{PATH}: count = 0 cost = 0
{PATH}: count = 2 cost = 2
{PATH}: count = 2 cost = 2
{WEIGHTED_PATH [REAL_32]}: count = 0 cost = 0
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{WEIGHTED_PATH [REAL_32]}: count = 2 cost = 7.6
{PATH_WITH_RECOMPUTE}: count = 0 cost = 0

fault_tester: system execution failed.
Following is the set of recorded exceptions:

-------------------------------------------------------------------------------
Class / Object Routine Nature of exception
Effect
-------------------------------------------------------------------------------
APPLICATION root's creation Segmentation violation:
<0000022F3C31F588> Operating system signal.
Exit
-------------------------------------------------------------------------------
APPLICATION root's creation
<0000022F3C31F588> Routine failure.
Exit
-------------------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~

If it's not a bug in the compiler then I eat my hat :-)

One possible workaround is to use REAL_64_REF instead of REAL
as generic parameter of WEIGHTED_EDGE, WEIGHTED_PATH and
WEIGHTED_PATH_WITH_RECOMPUTE. In that case there is no segmentation
violation when executing with EiffelStudio in workbench and
finalized mode because the compiler is not confused anymore between
reference and expanded types when redefining the signature of
cost/recomputed_cost from NUMERIC to C (the formal generic
parameter).

Jimmy Johnson

unread,
Jan 16, 2022, 11:46:44 AM1/16/22
to Eiffel Users
Yes.  I had forgotten (until I was in bed) that you had mentioned that a month ago and did not include that in my example.  Attached is a new APPLICATION class that demonstrates reference versus expanded types.
I guess we can conclude this thread until Eiffel Software provides a fix?
jjj
application.e

Ulrich Windl

unread,
Jan 17, 2022, 2:25:21 AM1/17/22
to eiffel...@googlegroups.com
Hi!

Well, this is not about the specific problem, but a general opinion on the problem:
If any Eiffel system was compiled successfully and gets a non-catchable segemntation fault during execution, then Eiffel is not better than C.
In general I think no system written in Eiffel should ever die due to a segmentation violation (maybe bugs in the OS or OS libraries excepted).
Segmentation violations (as well as the more obscure bus errors) are due to invalid memory access. Memory access errors should not happen in Eiffel (maybe unless one write some foreign language interfaces).

Regards,
Ulrich

>>> Jimmy Johnson <eiffe...@gmail.com> schrieb am 14.01.2022 um 20:49 in
Nachricht <1a742bab-06a0-4de2...@googlegroups.com>:
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/1a742bab-06a0-4de2-9ae1-9dd792
> f87948n%40googlegroups.com.




Eric Bezault

unread,
Jan 17, 2022, 2:41:02 AM1/17/22
to eiffel...@googlegroups.com
On 17/01/2022 8:25, Ulrich Windl wrote:
> Hi!
>
> Well, this is not about the specific problem, but a general opinion on the problem:
> If any Eiffel system was compiled successfully and gets a non-catchable segemntation fault during execution, then Eiffel is not better than C.
> In general I think no system written in Eiffel should ever die due to a segmentation violation (maybe bugs in the OS or OS libraries excepted).
> Segmentation violations (as well as the more obscure bus errors) are due to invalid memory access. Memory access errors should not happen in Eiffel (maybe unless one write some foreign language interfaces).

But in this case the segmentation violation is due to a bug
in the Eiffel compiler, not to a bug in the Eiffel program.
Again, the same Eiffel program compiled with the Gobo Eiffel
compiler works fine. So in that case it's not a problem with
the Eiffel language, and I don't think that we should draw
conclusion about whether Eiffel is better than C or not out
of this problem.

Ulrich Windl

unread,
Jan 17, 2022, 2:47:49 AM1/17/22
to eiffel...@googlegroups.com
>>> Eric Bezault <er...@gobosoft.com> schrieb am 17.01.2022 um 08:40 in Nachricht
<5a88a744-e000-74c2...@gobosoft.com>:
> On 17/01/2022 8:25, Ulrich Windl wrote:
>> Hi!
>>
>> Well, this is not about the specific problem, but a general opinion on the
> problem:
>> If any Eiffel system was compiled successfully and gets a non-catchable
> segemntation fault during execution, then Eiffel is not better than C.
>> In general I think no system written in Eiffel should ever die due to a
> segmentation violation (maybe bugs in the OS or OS libraries excepted).
>> Segmentation violations (as well as the more obscure bus errors) are due to
> invalid memory access. Memory access errors should not happen in Eiffel
> (maybe unless one write some foreign language interfaces).
>
> But in this case the segmentation violation is due to a bug
> in the Eiffel compiler, not to a bug in the Eiffel program.
> Again, the same Eiffel program compiled with the Gobo Eiffel
> compiler works fine. So in that case it's not a problem with
> the Eiffel language, and I don't think that we should draw
> conclusion about whether Eiffel is better than C or not out
> of this problem.
>

Eric,

we are both right: A language is only as good as its compiler.

Regards,
Ulrich


> --
> Eric Bezault
> mailto:er...@gobosoft.com
> http://www.gobosoft.com
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/5a88a744-e000-74c2-1dfc-5a5b33
> a48f48%40gobosoft.com.




Ian Joyner

unread,
Jan 17, 2022, 3:07:17 AM1/17/22
to eiffel...@googlegroups.com
On 17 Jan 2022, at 18:47, Ulrich Windl <Ulrich...@rz.uni-regensburg.de> wrote:
>
>>>> Eric Bezault <er...@gobosoft.com> schrieb am 17.01.2022 um 08:40 in Nachricht
>>
>> But in this case the segmentation violation is due to a bug
>> in the Eiffel compiler, not to a bug in the Eiffel program.
>> Again, the same Eiffel program compiled with the Gobo Eiffel
>> compiler works fine. So in that case it's not a problem with
>> the Eiffel language, and I don't think that we should draw
>> conclusion about whether Eiffel is better than C or not out
>> of this problem.
>>
>
> Eric,
>
> we are both right: A language is only as good as its compiler.

Not really. You can get a better compiler or fix the compiler. It is wrong to judge a concept by its implementation, although that is the way it might seem to the current user. But that is a narrow perspective.

Ian

Alexander Kogtenkov

unread,
Jan 17, 2022, 3:21:30 PM1/17/22
to eiffel...@googlegroups.com
Dear Jimmy,
 
Indeed, there is a bug in C code generation for a particular combination of anchored types and generic polymorphism, involving redeclaration of a reference type into an expanded one. We were trying to find a reasonable workaround, but according to your comments to the messages from the users of the mailing list, there is no way to get rid of the anchored type and to keep just the generic one. With such restrictions, the suggestion to stick to reference types as actual generic parameters in your classes seems most appropriate until the bug is fixed.
 
To guarantee that your system does not use an expanded type as the actual generic parameter, you can try the following non-standard extension:
 
   class WEIGHTED_PATH [reference C -> ...]
 
The keyword `reference` will tell EiffelStudio that any actual generic parameter should be a reference type, and will report an error for any attempt to use an expanded type instead.
 
Best regards,
Alexander Kogtenkov
 
 
Sunday, January 16, 2022 7:46 PM +03:00 from Jimmy Johnson <eiffe...@gmail.com>:
 
--

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.

Jimmy Johnson

unread,
Jan 17, 2022, 7:29:21 PM1/17/22
to Eiffel Users
Alexander,
Thanks for your response and workaround.  It's always nice to know if I'm messing up (which is usually the case).  I consider this thread completed.  Y'all really do great work providing us with Eiffel, and I greatly appreciate it.  I would not even attempt projects such as this one in any other language.
Thanks again,
jjj

Reply all
Reply to author
Forward
0 new messages