librelist archives

« back to archive

Various Liberty-related C++-induced issues (2nd try)

Various Liberty-related C++-induced issues (2nd try)

From:
Paolo Redaelli
Date:
2010-07-23 @ 06:52
I'm re-sending this to the mailing list after having sent it to Cyril.

I've been working for a while on a little
project of mine - a smartphone truss/beam solver. In order to grasp the
majority of the market and I've been working on Qt. 

That way I can
- target the vast majority of the deployed smartphones, which in Europe
and Asia which is Symbian/Nokia;
- use a free-as-in-freedom technology, 
- target emerging technologies also: there is a working version of Qt
for Android, and Qt will be foundation of Nokia/Intel Meego phones and
tables, so with the notable and almost desired exception of the
golden-prison iphone, this choice makes sense.
- pave the way for a Liberty based implementation.

So I installed QtCreator and returned coding C++. 

After a few days of coding I've now painfully recalled the many reasons
that made me switch to Eiffel after the C++ development I worked out in
my thesis. Working with QtCreator does not make things a lot easier. C++
coding is still painful from every point of view, I shall remember to
outline all the swearing I had when we will present Liberty to the
world...

So I decided I'll write a sketchy version in C++ while developing in
parallel the real one in Liberty. 

I encountered some issues these days I like to work out here on the
mailing list.

1) Is there a specific reason for iterators to be a reference class and
not expanded, except getting polymorphism? I've been documenting myself
of the techniques useful for smartphone development and one of the chief
guideline is to keep memory usage as low as feasible; allocating tiny
amounts of memory every time we use an iterator does not comply to this
rule, so why don't we provide in each container an expanded iterator,
maybe named iter? 
As far as can say all the iterators I saw are smallish objects and they
are usually not passed around. 
Let's say we have a newly converted C/C++ programmer; s/he shall write
the usual:

for(int i=0;i<=count;++i) {
foo = foos[i]; 
/* ..... */
}

as local i: INTEGER; f: FOO
do
from i:=0 until i<=count loop
f := foos@i
-- ...
i:=i+1
end
Eventually he will turn to

local i: ITERATOR[FOO]; f: FOO
do
from i:=foos.new_iterator; i.start; until i.is_off loop
f:=i.item
i.next
end

and finally to
foos.do_all (agent (x: FOO) is do
-- ....
end)

But the latter two will actually allocate memory. The
performance-conscius programmer will never give-up his
not-allocating-loop. An expanded iterator would satisfy him. As far as I
can say the fattest iterator from standard library is 12 bytes... it is
not that big to place on the stack... 



2) Namespaces: I was planning to naively wrap them as clusters. This
leave us with a problem that C++ coders don't have: multiple names. What
if we have MyClass in namespace Foo and also in Bar? C++ coder simply
solve this writing Foo::Myclass and Bar::MyClass. Yet many C++ libraries
clearly avoid such questions with the same prefix technique that is
widespread in C and in Eiffel: the Foo version will be named FooMyClass
and Bar's one BarMyClass. My idea is this in Eiffel-like code

wrappable: WRAPPABLE
if wrappable.name.has_prefix (wrappable.namespace.name) then
wrapper_name := wrappable.name
-- Most probably we won't overwrite symbols. The name already include
the namespace.
else
wrapper_name := namespace.name + wrappable.name
-- Let's add the namespace as prefix to avoid name clashes
end

3) C++ const is useful but it is a devilish construct, especially for
COLLECTIONs (C++/STL containers). Adding to COLLECTION this feature:

as_traversable: TRAVERSABLE[E_] is
-- Current collection as a read-only traversable object.
do 
    Result:=Current
end

may be useful in many cases where a class wants to provide its clients
read-only access to the collections composing the object itself. I'll
write a little mock-up in wrappers-generator's C_NAMESPACE soon.
Something like this:

class RECIPE
....
feature {ANY}
    ingredients: TRAVERSABLE[INGREDIENT] is 
        -- Read-only access to everyone
    do Result:=costituents.as_traversable end
feature {COOK}
    constituents: COLLECTION[INGREDIENT]
    -- Cooks are allowed to make changes!
end 

Actually we shall not need such a feature since this may be easily
obtained written that way:

class RECIPE
....
feature {ANY}
    ingredients: TRAVERSABLE[INGREDIENT] is 
        -- Read-only access to everyone
    do Result:=costituents end
feature {COOK}
    constituents: COLLECTION[INGREDIENT]
    -- Cooks are allowed to make changes!
end 


but I think that its presence will help the newbie programmer. 
Other than that.... 
Happy hacking
Paolo

PS: sometimes coding in other languages is instructive!
PPS: let's see if it arrives