Reply to topic  [ 7 posts ] 
keywords are extern variables by default 
Author Message
Yorick Guru

Joined: Wed Nov 24, 2004 12:51 pm
Posts: 97
Location: Observatoire de Lyon (France)
Post keywords are extern variables by default
For Yorick parser (I use the CVS version of 2010-11-15), a keyword is by default an extern variable. This is demonstrated by the following piece of code which show that extern variable "key" is set by function f2:
Code:
func f0(arg, key=)
{
  return arg;
}

func f1
{
  f0, key=1;
}

func f2
{
  f0, key=1;
  key = 222;
}

func f3
{
  local key;
  f0, key=1;
  key = 333;
}

key = [];
f1;
write, "f1 --> key =", print(key);

key = [];
f2;
write, "f2 --> key =", print(key);

key = [];
f3;
write, "f3 --> key =", print(key);


The output is:
f1 --> key = []
f2 --> key = 222
f3 --> key = []


Wed Nov 17, 2010 8:05 am
Profile WWW
Yorick Guru

Joined: Wed Nov 24, 2004 12:51 pm
Posts: 97
Location: Observatoire de Lyon (France)
Post 
(sorry I hit "submit" too fast)

The problem mentioned above is not the behavior that is documented in Yorick documentation and since it may have unwanted side effects, I think that the parser should be fixed.

The other possibility is to change the doc. but this behavior can hardly be seen as a feature. The scoping rules of Yorick (p. 11-12 of the manual) are simple but already somewhat perturbating for new users. If keywords are also external variables by default it would be very difficult even for a Yorick master to avoid conflicts.

I have tested an "old" (2.1.04) Yorick version and the problem is the same.


Wed Nov 17, 2010 8:17 am
Profile WWW
Yorick Guru

Joined: Wed Nov 24, 2004 12:51 pm
Posts: 97
Location: Observatoire de Lyon (France)
Post 
Sorry for insisting on this issue but it occured again to me, and I shooted in my foot :cry:.

In Yorick, the first time a symbol appears in the code flow of a function, it is considered as an external one unless it appears as the symbol defined by a simple assignation (as in: var = expr;) or unless it is a dereferenced member (as in: obj.memb; or ptr->memb;).

This means that in every line below, symbol foo is external by default while bar is not (db is a structure or any object which implements member dereferencing, ptr is a pointer on a such object, obj is an OXY object):
Code:
a = foo(b);
a = db.bar;
a = ptr->bar;
a = fn(x, foo=7);
a = obj(foo, 45, 21);
Except for the three first examples (the function call and member dereferencing), this behaviour is not really intuitive. I guess from this observed behavior that the parser is able to recognize member dereferencing, hence it should be possible to solve the issue for and fourth case (keyword). Due to dynamic typing, the parser cannot be fixed to solve for the last case (OXY dereferencing or method calling).


Wed Dec 22, 2010 1:46 am
Profile WWW
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post 
I had not realized this misfeature. The above analysis is incorrect, however -- this is an exceedingly subtle point. There are actually THREE possible states for a literal name in a yorick function: It may be local, it may be extern, or it may be undecided. The correct behavior for a keyword argument when the keyword name has never been mentioned SHOULD be that it remains undecided. This is because the keyword name belongs to the namespace of the function being called, not to the namespace of the caller. For example, the name of a member after the . or -> operators does not belong to the namespace of the function, but to the namespace of the struct or object -- therefore using a member name in a function leaves the name undecided, that is, you are still free to declare it either local or extern. Both these are legal:
Code:
func f { g.name; extern name; }
func f { g.name; local name; }


Compare this to:
Code:
func f { g,name=7; extern name; }
func f { g,name=7; local name; }

The second of these has always been a syntax error, because the use of name as a keyword (thus belonging to the namespace of g) incorrectly forces name to be an extern if it has not already been declared. In other words, using a name as a keyword incorrectly constitutes a first reference in a caller if that name has never been used.

Unfortunately, the parser is written so that it would be very difficult to do the correct thing, and leave the keyword name undecided, so that neither of the sample f functions is a syntax error. I agree with Eric to the extent that if I must have incorrect behavior, it would be better to err in the opposite direction and make the (incorrect) choice that the first reference of a name as a keyword produces a local. Therefore, I have committed a change to the parser which produces the opposite behavior henceforward.

I'll probably regret this change, as it may well break code that had previously worked. As in all cases where yorick's informality causes problems, this one could have been avoided (and still can be avoided) by putting an explicit local or extern declaration before the use of a symbol as a keyword.

Be warned that if I ever get around to rewriting the parser, this behavior will change once again, so that using a name as a keyword leaves its status as a variable undecided, just as using it as a member name (for either the . or -> operator) currently, and correctly, leaves its status undecided. In the meantime, if you want really bulletproof code and you refuse to use explicit extern and local declarations, you should avoid using keyword names to implicitly declare variable scope, by altering the names of any of your own variables so they do not conflict with keyword names in functions you call.

Eric's analysis of the problem with the oxy syntax is absolutely correct -- the use of obj(foo) unexpectedly causes foo to take on extern scope if you use it elsewhere in your function. This is (another) misfeature of the object semantics I invented. You need to either explicitly or implicitly declare foo before this use, or better yet, avoid using foo as a local variable name whenever possible.


Wed Dec 22, 2010 2:07 pm
Profile
Yorick Guru

Joined: Sat Jan 22, 2005 2:44 pm
Posts: 86
Location: Pasadena, CA
Post 
"hcp" undifined in graph.i - hcps
Is this an example of the side effect you mentioned?
fix:
Code:
RCS file: /cvsroot/yorick/yorick/i0/graph.i,v
retrieving revision 1.14
diff -r1.14 graph.i
274a275
>   extern hcp;


Wed Jan 05, 2011 11:53 am
Profile YIM
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post 
It is indeed. I fixed this in CVS, but I really hope it isn't too common. I'm regretting the change already, since the code that produces either misbehavior looks right -- it almost certainly would have been better to stick with the original choice... I'll leave it as is for now, and hope that there aren't more examples like this lying in wait...


Sat Jan 08, 2011 5:20 pm
Profile
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post Re: keywords are extern variables by default
This issue is finally correctly resolved. If the first reference to a symbol in a function is as a keyword, yorick no longer forces the symbol to have either local or extern scope in the function. This prevents either common use case from giving unanticipated results. See https://github.com/dhmunro/yorick/commi ... 352d3402fd for details.


Sun Mar 06, 2011 2:56 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 7 posts ] 

Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by STSoftware for PTF.