1. SS
- Posted by Karl Bochert <kbochert at copper.net> Jan 06, 2007
- 575 views
Having seen some of the misunderstandings, I would like to re-present my SS proposal in different words. Perhaps I can be clearer. StructureS
-- Define a structure structure Point is atom x, y end structure
A piece of data named Point is created. It has 2 elements which can only be accessed by name The values of the elements are always initialized, to 0 if not otherwise specified.
?Point.x --> "0.0" ?Point.y --> "0.0" Point.x += 3.0 Point.y = Point.x + 1.0 ?Point.x --> "3.0" ?Point.y --> "4.0"
The ids used for the members ( x and y) are available only in the Point namespace, not globally so:
?Point.x --> "3.0" ?x -- ERROR not defined integer x x = 1 ?x --> "1" ?Point.x --> "3.0"
In addition to holding some data, Point may be used as a prototype to create new data. It provides both the structure and the data to the new item.
Point p1 ?p1.x --> "3.0" ?p1.y --> "4.0"
The newly created structure has all the attributes of a structure and can be used to create further structures
p1.x = 2.0 p1 p2 ?p2.x -> "2.0"
-- extends A structure may be declared as being an extension of another, in which case it has all the elements of the structure being extended and any new items it declares
structure Point3d extends Point atom z end structure ?Point3d.z --> "0.0" ?Point3d.x --> "2.0" --Point.x was set above, and copied into Point3d
The not-notation is fully nestable so:
structure color is integer r, g, b end structure structure ColorPoint extends Point color mycol end structure ?ColorPoint.color --> "<0,0,0>" ?ColorPoint.color.r --> "0"
Note how ColorPoint.color is printed. A structure is NOT a sequence! KtB
2. Re: SS
- Posted by cklester <cklester at yahoo.com> Jan 06, 2007
- 559 views
- Last edited Jan 07, 2007
Karl Bochert wrote: > > A structure is NOT a sequence! I have not investigated this to any great extent. What I'd like to do is review some of the code I've written and see how structures would make it better. Having said that, I like Karl's definition of structures a lot. And here's the rationale that justifies adding it to official Euphoria: 1. Adds useful functionality that cannot be otherwise added with an include file. 2. Backward compatible. All current Euphoria code will work without change. 3. Makes Euphoria even more flexible and powerful. Now, how much of a performance hit would current Euphoria programs take if using an interpreter that included structure functionality? Matt has added something very similar (even more advanced) to OOEU, and he says that performance has not decreased significantly ("should be very similar" in speed). I suspect that native structures would improve performance of current Euphoria code that used some kind of work-around to emulate structures. Who wants to prove that? Karl? :) Regardless, structures should get the go-ahead on more investigation. :) -=ck "Programming in a state of Euphoria." http://www.cklester.com/euphoria/
3. Re: SS
- Posted by James W Hofmann <jhofmann at ucsc.edu> Jan 06, 2007
- 569 views
- Last edited Jan 07, 2007
I think this is good. One addition, though: Although we've now distinguished the structure as its own type, there should exist a standard method of translating between sequence and structure. The rationale I have is that if you want to serialize data in a file or a stream the sequence is a more natural type to use, but without the interpreter's help you will have to write a custom translation function for each different structure:
-- we have defined a 2d Point p that we wish to translate to -- a sequence, and then back again function PointToSeq(Point p) sequence s s = {p.x,p.y} return s end function function SeqToPoint(sequence s) Point p p.x = s[1] p.y = s[2] return p end function Point p sequence s s = PointToSeq(p) p = SeqToPoint(s)
In a large program this code is going to be a lot of additional work to maintain. We could implement a generic version to do the same job instead:
-- same Point and sequence types, but no need for new functions Point p sequence s s = toseq(p) -- output is currently undefined p = tostruct(s) -- tostruct takes the type of p (so it knows to use -- a Point)
This doesn't cover the order of the resulting sequence, but it is presumably self-consistent. Remember, the point is to be able to serialize all our data. It's still the user's job to maintain a method of identifying structures within the resulting sequence.
4. Re: SS
- Posted by Chris Burch <chriscrylex at aol.com> Jan 07, 2007
- 565 views
Karl Bochert wrote: > > Having seen some of the misunderstandings, I would like to > re-present my SS proposal in different words. Perhaps I can be clearer. > > StructureS > }}} <eucode> > -- Define a structure > structure Point is > atom x, y > end structure > </eucode> {{{ > A piece of data named Point is created. > It has 2 elements which can only be accessed by name > The values of the elements are always initialized, to 0 if not > otherwise specified. > }}} <eucode> > ?Point.x --> "0.0" > ?Point.y --> "0.0" > Point.x += 3.0 > Point.y = Point.x + 1.0 > ?Point.x --> "3.0" > ?Point.y --> "4.0" > </eucode> {{{ > The ids used for the members ( x and y) are available only in > the Point namespace, not globally so: > }}} <eucode> > ?Point.x --> "3.0" > ?x -- ERROR not defined > integer x > x = 1 > ?x --> "1" > ?Point.x --> "3.0" > </eucode> {{{ > > In addition to holding some data, Point may be used as a prototype to > create new data. It provides both the structure and the data to the new > item. > }}} <eucode> > Point p1 > ?p1.x --> "3.0" > ?p1.y --> "4.0" > </eucode> {{{ > The newly created structure has all the attributes of a structure > and can be used to create further structures > }}} <eucode> > p1.x = 2.0 > p1 p2 > ?p2.x -> "2.0" > </eucode> {{{ > > > -- extends > A structure may be declared as being an extension of another, in which > case it has all the elements of the structure being extended and any new > items it declares > }}} <eucode> > structure Point3d extends Point > atom z > end structure > ?Point3d.z --> "0.0" > ?Point3d.x --> "2.0" --Point.x was set above, and copied into Point3d > </eucode> {{{ > > The not-notation is fully nestable so: > }}} <eucode> > structure color is > integer r, g, b > end structure > structure ColorPoint extends Point > color mycol > end structure > ?ColorPoint.color --> "<0,0,0>" > ?ColorPoint.color.r --> "0" > </eucode> {{{ > > Note how ColorPoint.color is printed. > A structure is NOT a sequence! > > KtB I actually quite like this idea too. I see you could have structures within structures. Under this definition, could you have a sequence contain structures? eg
-- Define a structure structure Point is atom x, y end structure sequence my_sequence my_sequence = repeat(Point, 10) my_sequence[5].x = 4
ie, arrays Chris http://euallegro.wikispaces.com http://members.aol.com/chriscrylex/euphoria.htm http://uboard.proboards32.com/ http://members.aol.com/chriscrylex/EUSQLite/eusql.html
5. Re: SS
- Posted by Karl Bochert <kbochert at copper.net> Jan 07, 2007
- 542 views
Chris Burch wrote: > I actually quite like this idea too. > > I see you could have structures within structures. > > Under this definition, could you have a sequence contain structures? > eg > }}} <eucode> > -- Define a structure > structure Point is > atom x, y > end structure > > sequence my_sequence > my_sequence = repeat(Point, 10) > > my_sequence[5].x = 4 > Yes, sequences of structures are possible and important but... my_sequence[5].x = 4 How is Eu to know that the object in [5] is a Point structure? One solution would be run-time lookup. The object stored in [5] is tagged as a Point. Eu then knows it must store 4 in one of a Point's members, but which one?? At compile time Eu knows where x is only if it knows what structure is in [5] (Other structures may have a member named 'x') I don't know if I've explained that well, but the upshot is that it is a can of worms, and very slow if possible at all. The best possibility that I can see is for the programmer to tell Eu what kind of structure to expect. For instance: <Point>my_sequence[5].x = 4 or Point:my_sequence[5].x = 4 or Point = my_sequence[5] Point.x = 4 or ??? With this information, Eu can generate the appropriate code, including run-time verification that the object in [5] really is a Point. KtB
6. Re: SS
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Jan 07, 2007
- 548 views
Karl Bochert wrote: > my_sequence[5].x = 4 > > How is Eu to know that the object in [5] is a Point structure? Oh my, yep. A long time ago now, I figured it would not be completely impractical to have a "last verified as udt" field on every sequence, tho obviously you cannot on a short int and it would just not be worth it on a float. Problem is that eg:
for i=1 to length(list) do ?list[i].phone end for
Effectively ".phone" might be [15] for customers, [17] for suppliers, and invalid subscript on anything else. Nasty. Possibilities still exist with "sequence of customer" etc, but the problems and limitations are mounting up now I feel. Fun while it lasted, though. Regards, Pete
7. Re: SS
- Posted by Matt Lewis <matthewwalkerlewis at gmail.com> Jan 07, 2007
- 534 views
Chris Burch wrote: > > I actually quite like this idea too. > > I see you could have structures within structures. > > Under this definition, could you have a sequence contain structures? > eg > }}} <eucode> > -- Define a structure > structure Point is > atom x, y > end structure > > sequence my_sequence > my_sequence = repeat(Point, 10) > > my_sequence[5].x = 4 > > </eucode> {{{ > > ie, arrays > Yes, I think this is important, and I put this feature (still a bit buggy, I think) into ooeu, although you have to declare:
sequence of Point points
Of course, one difference is that my class objects are really just sequences (or possibly atoms), and there is no way for the backend to know that it's dealing with a specific class unless it's declared. I'm still not on board with the idea that "structures aren't sequences." Partly for implementation issues, partly because I think it de-simplifies the language needlessly. Matt
8. Re: SS
- Posted by Matt Lewis <matthewwalkerlewis at gmail.com> Jan 07, 2007
- 572 views
Pete Lomax wrote: > > Problem is that eg: > }}} <eucode> > for i=1 to length(list) do > ?list[i].phone > end for > </eucode> {{{ > Effectively ".phone" might be [15] for customers, [17] for suppliers, and > invalid > subscript on anything else. Nasty. Proper OO design would put the 'phone' member into a super class of both, so that they would be inheriting the same thing, and the indices would be the same. In a related vein, for 'true' OOP, you really need late binding, which basically means virtual functions. I think this is very doable for ooeu. My idea is that, as soon as the user declares a routine as virtual, a data member vtbl is automatically added (if it hasn't already). Or maybe it's just something that's invisible to the coder, which might make initialization easier...but I'm getting off topic. The basic idea would allow something like the following:
euclass person( sequence p ) sequence name virtual procedure print_name() end procedure end euclass person euclass customer( person c ) virtual procedure print_name() printf(1,"Customer: %s\n", {this.name}) end procedure end euclass euclass supplier( person s ) virtual procedure print_name() printf(1,"Supplier: %s\n", {this.name}) end procedure end euclass customer cust = {"Matt"} supplier supp = {"Pete"} sequence of person people people = {cust, supp} for i = 1 to length(people) do people[i].print_name() end for -- Output: -- Customer: Matt -- Supplier: Pete
> Possibilities still exist with "sequence of customer" etc, but the problems > and limitations are mounting up now I feel. Fun while it lasted, though. I agree with you if we are still talking about the types of structures that Karl had proposed (and basically agree with Rob, especially about the backend issues). However, I don't see a problem with the sort of thing I've done with ooeu. My approach, I suppose, is to allow the user to have extra tools for dealing with data. It allows a different way to organize and use the data, but doesn't preclude using it in a normal way, or in a halfway mode that uses more dots, but doesn't use the same OOP-style syntax:
? cust[customer.name] customer.print_name( cust )
Matt
9. Re: SS
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Jan 09, 2007
- 549 views
Matt Lewis wrote: > In a related vein, for 'true' OOP, you really need late binding, which > basically means virtual functions. I think this is very doable for ooeu. I'm pretty sure you are talking about precisely the stuff I "don't get". Erm... > }}} <eucode> > euclass person( sequence p ) > sequence name > virtual procedure print_name() > end procedure > end euclass person umm... > for i = 1 to length(people) do > people[i].print_name() > end for Youch! That kinda means that an integer has to have a virtual function of the same name... ?? > backend issues). However, I don't see a problem with the sort of thing > I've done with ooeu. Speaking of which, do you have any sort of design doc about ooeu's pbr? Pete PS is that what "virtual" actually means, ie "late binding"?
10. Re: SS
- Posted by Matt Lewis <matthewwalkerlewis at gmail.com> Jan 09, 2007
- 542 views
Pete Lomax wrote: > > Matt Lewis wrote: > > In a related vein, for 'true' OOP, you really need late binding, which > > basically means virtual functions. I think this is very doable for ooeu. > I'm pretty sure you are talking about precisely the stuff I "don't get". > Erm... > > }}} <eucode> > > euclass person( sequence p ) > > sequence name > > virtual procedure print_name() > > end procedure > > end euclass person > umm... > > for i = 1 to length(people) do > > people[i].print_name() > > end for > Youch! That kinda means that an integer has to have a virtual function > of the same name... ?? It's not the integer that has a function. It's the euclass 'person' and its various subclasses that have this function. > > backend issues). However, I don't see a problem with the sort of thing > > I've done with ooeu. > Speaking of which, do you have any sort of design doc about ooeu's pbr? No. Just the implementation and the documentation in the ooeu docs. It works slightly differently in the eu backend and the c backend. There's a real performance benefit in the c backend, because I avoid COW by not Ref'ing and DeRef'ing. The basic idea is that you declare pbr in the routine declaration. Whenever the routine is called, the interpreter checks to see if the pbr parameter is a normal var (no temps, literals, constants or loop vars). If it is, then it remembers where it came from. When the routine returns, it looks again to see if it remembers any pbr variables. If there were any, then it updates the source variable. In the eu-backend, it's just a regular eu data copy, so you don't get any speedups. In the c-backend, it's just a copy of a pointer in the SymTab, so it gives a nice speed boost when working with a large sequence repeatedly. > Pete > PS is that what "virtual" actually means, ie "late binding"? Basically. In the example I gave, you have the euclass person. A person has a method that prints out his name. I've also created subclasses that use person--basically more detailed person classes. This allows me to do some specific things. However, some parts of my code may want to do certain things with respect to persons. I'd like to be able to call the correct routine to get that specialized routine, but I'd like to be able to keep my code as generic as possible to prevent duplication and code bloat (i.e., a big if-then to call person.print, customer.print, supplier.print, etc). Early binding occurs when the actual routine can be resolved at compile time. Late binding is when the actual routine is not resolved until runtime, like using routine_ids. In the above case, I'm telling the interpreter that I'm handing it a person, which may be a subclass which will override the default behavior. The interpreter will have to have information stored with the data that allows it to resolve the proper routine to call. For ooeu, it would likely be a data member called vtbl that has a bunch of routine ids. Using the knowledge of the base class type (person) and the vtbl data supplied by the actual data, the interpreter resolves which routine to be called, and calls it. Matt
11. Re: SS
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Jan 09, 2007
- 553 views
Matt Lewis wrote: > The basic idea is that you declare pbr in the routine declaration. > Whenever the routine is called, the interpreter checks to see if the > pbr parameter is a normal var (no temps, literals, constants or loop vars). > If it is, then it remembers where it came from. I see. Any thoughts on what you could do in the front end for update(a[i])? As you said, the back-end will only get to see a tmp, the front end would need to emit an additional a[i]=tmp, perhaps. Regards, Pete
12. Re: SS
- Posted by Matt Lewis <matthewwalkerlewis at gmail.com> Jan 09, 2007
- 549 views
Pete Lomax wrote: > > Matt Lewis wrote: > > The basic idea is that you declare pbr in the routine declaration. > > Whenever the routine is called, the interpreter checks to see if the > > pbr parameter is a normal var (no temps, literals, constants or loop vars). > > If it is, then it remembers where it came from. > I see. Any thoughts on what you could do in the front end for update(a[i])? > As you said, the back-end will only get to see a tmp, the front end would > need to emit an additional a[i]=tmp, perhaps. Yeah, something like that. I'm not sure on the details. It'll involve some extra front end and backend work, though. Matt