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