Re: Type - Start Again
- Posted by CChris <christian.cuvier at agriculture.g?uv.?r> Aug 20, 2007
- 515 views
Pete Lomax wrote: > > Salix wrote: > > > > }}} <eucode> > > type customer(sequence x) > > integer x[1] as id > > sequence x[2] as name > > sequence x[3] as address > > end type > > </eucode> {{{ > > > > I would like to hear your opinion on the > > simplification shown above. What do you think? > > > I can accept that, with some qualifications (see below) > > Peter Robinson wrote: > > Once you accept a declarative shorthand for boolean expressions, > > the following is equally intuitive:- > > > > type ten_ints( sequence x ) > > length(x) = 10 – insert any boolean expression you want > > end type > > > > Since type blocks are just a series of boolean expressions, why not ASSUME > > that in a declarative syntax? > But they are not. Types can be very useful in debugging, eg if I notice that > my program has crashed because something has set bCFwd[31][2] to -7, then I > can find where that happened by using a type, with any of: > }}} <eucode> > if x[31][2]=-7 then return 0 end if > if x[31][2]=-7 then ?9/0 end if > if x[31][2]=-7 then trace(1) end if > </eucode> {{{ > > Currently types, like functions and procedures, have implicit <locals> and > <code> > sections. I can accept this be changed to <fields> <locals> <code>. > But I would not be happy with a change that meant type definitions could no > longer hold local vars and code. > > CChris wrote: > > Looks nice, but the parser will have a terrible time with this... > It all seems pretty straightforward to me: > }}} <eucode> > -- in type/routine definition (pseudocode) > if <rtn type>=E_Type and <param type>=T_Sequence then > -- process (optional) fields section: > while isType() do > nextToken() > if tok[ID]!=<parameter> then > -- complete first local var specially, since we accidentally > -- just "ate" the sequence/integer/etc token [if needbe] > exit > end if > expect "[" > ... > end while > end if > -- existing handling for <locals> and <code> follows > </eucode> {{{ That's the first ... section which worries me a little because of some corner cases. > In the same way that <locals> must be defined before <code>, keep it simple by > ruling that <fields> must be defined before <locals>. > Agreed. > The scope of id,name,address etc is a far trickier problem, imo. Nope, they have the same scope as the type they appear in, but should not be used as indexes for the type they are defined for. The dot syntax appears to be just fine. Using ':' like for a namespace is tempting, but would create nasty collisions, so I'd prefer using the dot. Remember I'm an heretic from the procedural religion. > The only thing > I could suggest is have a look at the $ handling, however while > mycustomer[name] > is fine, mycustomer[f(name)] would not be... Also, in > > }}} <eucode> > type address(sequence x) > sequence x[1] as addr1 > sequence x[2] as addr2 > end type > type customer(sequence x) > integer x[1] as id > sequence x[2] as name > address x[3] as addr > end type > ... > .. mycustomer[<xxx>][<yyy>] .. > ... > </eucode> {{{ Could you make it simpler by omitting the numbers, since they are defined by the statement # they appear in? This would lead to:
type address(sequence x) fields sequence addr1 sequence addr2 end fields <optional normal routine body here> end type type customer(sequence x) fields integer id sequence name address addr end fields end type ... if equal(mycustomer[<xxx>][customer.name],"Pete") then ... ...
assuming mycustomer is a "sequence of customer", or a "customer list", which I'd prefer as closer to the coder's intent. > Then id,name,addr would be valid for <xxx>, but addr1 and addr2 would only > be valid for <yyy> if <xxx> was (?the literal constant?) addr, and of > course all invalid elsewhere on that line (barring another customer var > subscript). > > Oh (and this was going to be a short post), is this going to be annoying? > }}} <eucode> > procedure showName(object x) > if customer(x) then > puts(1,x[name]) > ^ invalid > </eucode> {{{ > Of course when someone comes and optimises their code it must still work: > }}} <eucode> > procedure showName(object x) > integer cx > cx=customer(x) > if cx then > puts(1,x[name]) > </eucode> {{{ > Now /that/ is something a human sees well but gives a parser nightmares > Use x[customer.name], and the parser will be happy, won't he? Plus, if you use the wrong constant, you can get an error (customer.name may be 2 and supplier.name may be 4). The extra typing is a problem. To alleviate it, we'd have to be sure that x is a variable defined to be from a specific type with fields, and then forgetting the explicit "customer." would cause it to be assumed. If the condition is not met, then I'm not sure whether to throw an error. Could be the best thing to do. If you use a dotted constant with the wrong type, then it may be assumed that you know what yu are doing, so no error should occur. Probably a warning, just in case you didn't know what you were doing. > This is also getting perilously close to puts(1,x[name]) implementing late > binding, > but for that you would need to declare customer as an OO class. > > In fact on that note...... > > > This way we would extend types to _also_ include heterogeneous sequences, > I would imagine that > }}} <eucode> > type x(sequence of <type> y) > </eucode> {{{ > means it cannot have a fields section, a simple "and not <someflag>" after > the E_Type test above. Of course you cannot have a fields section on a type > declared > as integer, atom, or object (assuming we get the ret 0 fix) either. > Agreed for both points. CChris > Regards, > Pete