Let the compiler dispose of an expanded value

Note: I wrote this notes on august 2021, but I shall publish them now in the state thay are otherwise I will lose memory of their existence yet another time…

Lately I discovered that Liberty Eiffel needs expanded classes to be DISPOSABLE to get rid of a garbage collector like Rust does.

So I was quite disappointed to discover that currently a simple source like

class DISPEXPEX -- disposable expanded example
create {ANY} make
feature {ANY}
   make
      local a: DISPEXP
      do 
         print(a.out)
      end
end   

expanded class DISPEXP -- Disposable and expanded
insert DISPOSABLE
feature {ANY}
      name: STRING
      value: INTEGER
feature {} 
      dispose 
         do 
               print("disposing DISPEXP")
            end
         
end

does not even compile. It seems that DISPEXP must redefine out to let people actually use it. But changing DISPESP to

expanded class DISPEXP
   -- Disposable and expanded
insert DISPOSABLE
   redefine out end
feature {ANY}
      name: STRING
      value: INTEGER
      out: STRING
   do
      if name/=Void then
         Result := "DISPEXP"+name+" "+value.out
      else
         Result := "nameless DISPEXP"
      end
end
feature {} 
      dispose 
         do 
               print("disposing DISPEXP")
            end
         
end

doesn’t work as the compiler says that

****** Error: Invalid usage of feature `to_pointer' of class ANY. (The target which is of type DISPEXP cannot be converted to a memory address.)

The source lines relevant to this message are the following:

Line 421 column 4 in ANY (/home/paolo/src/liberty-eiffel/src/lib/kernel/any.e):
   to_pointer: POINTER
   ^                  
Line 8 column 16 in DISPEXPEX (/home/paolo/tmp/dispexpex.e):
         print(a.to_pointer.out)

Most programmers would have already rejected Eiffel by now. First of all why – for Heaven sake – doesn’t to_pointer have a require not is_expanded?

The answer is simple: ANY does not have an is_expanded or a is_reference feature. At first I was going to write it as

is_expanded: BOOLEAN do Result :=

instead it seems that introspection – i.e the usage of internals which require explicit support from the compiler – is not required as it can be implemented as

is_expanded: BOOLEAN local like_current: like Current do Result := like_current /= Void end

but it cannot work. In fact the compiler (correctly) argues that

****** Error: Such a weird comparison with Void is not allowed because it would be always True. (See explaination below.)

Line 21 column 27 in DISPEXP (/home/paolo/tmp/dispexp.e):
   Result := like_current /= Void
                          ^      
------
****** Fatal Error: The declaration type of `like_current' is obviously expanded (i.e. the written type mark is "DISPEXP"). You can use the Void comparison only when other type mark is a reference type or, if it is an expanded type, it must be an anchor or some formal generic argument. Fix this error first.

So in the end one could write ANY’s is_expanded as

is_expanded: BOOLEAN do Result := to_interals.type_is_expanded end

that implies that a simple class such as DISPEXP must insert INTERNALS_HANDLER.

So now we understand why to_pointer is built not to even compile when used on expanded values. It is a simplification that made life quite simpler to implementors.

There’s a issue. Why did they add “to_pointer” at all? You may promptly answer: because you need it to interact with low-level code. But we do have the $ operator for this. And wonder of wonders, it works smoothly on expanded objects. But it is meant to be used on the final name of a feature which is not a constant attribute or by the name of some local variable. Not even Current. If it wasn’t for the latter limitation one could write to_pointer: POINTER do Result := $Current end

… more on this later

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.