librelist archives

« back to archive

Various Liberty-related C++-induced issues

Various Liberty-related C++-induced issues

From:
Paolo Redaelli
Date:
2010-07-23 @ 05:38
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!


Various Liberty-related C++-induced issues

From:
Paolo Redaelli
Date:
2010-08-05 @ 07:13
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: I think I already sent it some days ago, sorry for eventual
inconvenince.

Re: [libertyeiffel] Various Liberty-related C++-induced issues

From:
Cyril Adrian
Date:
2010-08-05 @ 15:24
Hi Paolo, all,

On Thu, Aug 5, 2010 at 09:13, Paolo Redaelli <paolo.redaelli@gmail.com>wrote:

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

great :-)

1) Is there a specific reason for iterators to be a reference class and
> not expanded, except getting polymorphism?


Hem... To me polymorphism is not a small quality but the most important one.
I wouldn't relinquish that.

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

If we write a good GC it's not a real problem. Eiffel-level "allocation" is
simply a reuse of the same memory block since, as you rightly say, iterators
are mostly local.

Note that SmartEiffel's GC works with separate memory zones for each runtime
type, which greatly simplifies memory allocation.

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
>

Liberty's is the same as SmartEiffel's approach: name distance. If
Foo::Myclass if nearer from the client class than Bar::Myclass then the
former will be selected by default. Note that the distance calculus takes
into account subclusters.

In my experience, it is really rare to need both Foo::Myclass and
Bar::Myclass in the same client class; if it were to happen, Liberty's
configuration files will provide renaming facilities.

Cluster names belong to configuration files; classes should not need them.


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

I think it is useless. The argument to help newbies is to help them learn
proper inheritance, not to provide clunky features.

PS: sometimes coding in other languages is instructive!
>

Yes, but it is not a reason to pour every other languages crap into Eiffel.
Let's think first, and keep only really great ideas; once something is
provided it can never be removed.

Cheers,
-- 
Cyril *ADRIAN*

*http://www.cadrian.net/cyril*

*http://www.viadeo.com/invitation/cyril.adrian*<http://www.viadeo.com/invitation/cyril.adrian>

Re: [libertyeiffel] Various Liberty-related C++-induced issues

From:
Paolo Redaelli
Date:
2010-08-06 @ 16:25
Il giorno gio, 05/08/2010 alle 17.24 +0200, Cyril ADRIAN ha scritto:
.... 

>         1) Is there a specific reason for iterators to be a reference
>         class and
>         not expanded, except getting polymorphism? 
> 
> 
> Hem... To me polymorphism is not a small quality but the most
> important one. I wouldn't relinquish that.
> 
> 
> 
>         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... 
> 
> 
> If we write a good GC it's not a real problem. Eiffel-level
> "allocation" is simply a reuse of the same memory block since, as you
> rightly say, iterators are mostly local.
> 
> Note that SmartEiffel's GC works with separate memory zones for each
> runtime type, which greatly simplifies memory allocation.

Those arguments would satisfy most programmers with the exception of one
notable field: real-time applications. 
Time and space boundaries is one of the first arguments raised against
GC of any kind.
It's easy and feasible at least from my point of view to tell them to
acquire/create/allocate all the resources they need - reference objects,
iterator included - before entering critical sections of the code; I'm
not sure those programmers will be fine to create all the iterators
before they enter real-time sections; I'm not sure that this approach
can be feasible for all iterations; in fact the question turns into: "is
there any kind of real-time application that cannot know the number of
iterators they need?" Now some soft-rt OS like Symbian impones to its
application a limit to the size of the stack, so at least they do not
consider arbitrary deep recursion an option. 
Your doubts are sound: we cannot twist all the collections becuase a
field needs expanded collections; a more correct approach is to provide
a specialized cluster with all the features that will satisfy real-time
requirements such as expanded iterators.


>         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 
> 
> 
> Liberty's is the same as SmartEiffel's approach: name distance. If
> Foo::Myclass if nearer from the client class than Bar::Myclass then
> the former will be selected by default. Note that the distance
> calculus takes into account subclusters.
> 
> In my experience, it is really rare to need both Foo::Myclass and
> Bar::Myclass in the same client class; if it were to happen, Liberty's
> configuration files will provide renaming facilities.

Indeed that's also my experience... 
Member class functions overloading will be particurarly cumbersome. Qt
for example QGraphicsScene.item is overloaded seven times; I would
naively wrap overloaded function "foo" several times appending each time
the types of the arguments but I suspect this could become annoying. Let
me try to get some working example with Qt wrappers. When we get them
wrapped any other C++ library will be tamable.


> Cluster names belong to configuration files; classes should not need
> them.




> I think it is useless. The argument to help newbies is to help them
> learn proper inheritance, not to provide clunky features.

Indeed, this is a issue that shall be explained either in books or in
the documentation of the COLLECTION, I think I will try to add that to
my tree.


> Yes, but it is not a reason to pour every other languages crap into
> Eiffel. Let's think first, and keep only really great ideas; once
> something is provided it can never be removed.

Agreed. <StarWarish> I was almost attracted to the dark side (C++) of
the force, master Cyril :) </StarWarish>

Happy hacking
    Paolo

Re: [libertyeiffel] Various Liberty-related C++-induced issues

From:
Cyril Adrian
Date:
2010-08-06 @ 18:08
On Fri, Aug 6, 2010 at 18:25, Paolo Redaelli <paolo.redaelli@gmail.com>wrote:

>  Your doubts are sound: we cannot twist all the collections becuase a field
> needs expanded collections; a more correct approach is to provide a
> specialized cluster with all the features that will satisfy real-time
> requirements such as expanded iterators.
>

I would have answered exactly that if you didn't. Let's keep iterators as
they are. Those who need specific tools may also contribute the code. We
cannot provide for each and every whim.

 I think it is useless. The argument to help newbies is to help them learn
> proper inheritance, not to provide clunky features.
>
> Indeed, this is a issue that shall be explained either in books or in the
> documentation of the COLLECTION, I think I will try to add that to my tree.
>

Yes.


>  Yes, but it is not a reason to pour every other languages crap into
> Eiffel. Let's think first, and keep only really great ideas; once something
> is provided it can never be removed.
>
> Agreed. <StarWarish> I was almost attracted to the dark side (C++) of the
> force, master Cyril :) </StarWarish>
>

Back to the light welcome you are, young padawan  :-)

Have nice holidays!

Cheers,
-- 
Cyril *ADRIAN*

*http://www.cadrian.net/cyril*

*http://www.viadeo.com/invitation/cyril.adrian*<http://www.viadeo.com/invitation/cyril.adrian>