Reply to topic  [ 13 posts ] 
yorick 2.2 development begins 
Author Message
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post yorick 2.2 development begins
I committed the first yorick 2.2 code to CVS this morning. The version number is 2.2.00x. There is no 2.2.00; the first stable release of 2.2 will be 2.2.01. The final 2.1 version is 2.1.99, tagged y_2_1_99 in CVS.

The version number increments in honor of the first significant new feature in yorick in a long time: an object oriented extension, "oxy". When you build 2.2.00x, do help,oxy; help,save; help,is_obj to get a fairly comprehensive explanation of the new features. What I implemented was quite similar to the description in the forum post http://yorick.sourceforge.net/phpBB2/viewtopic.php?t=273.

The new "group" object makes _lst, struct, and pointer obsolete in interpreted code. The group object integrates much better into yorick's declarative-free, informal language than these now-obsolete borrowings from Lisp and C. Soon, groups will be able to be written directly to binary files using save and restore, at which point there will be scant excuse for not using them.

The 2.2 version also includes Eric Thiebaut's closure objects, which provide a clean alternative to using external variables to pass hidden arguments to callback functions.

You can look in i/testoxy.i for usage examples. Discussion is welcome; make a new topic in the Discussion and Support forum.


Sat Jul 03, 2010 12:53 pm
Profile
Yorick Guru

Joined: Sat Jan 22, 2005 2:44 pm
Posts: 86
Location: Pasadena, CA
Post testoxy.i
Thank you Dave.

Some typos that produce failure in make check ....

Code:
RCS file: /cvsroot/yorick/yorick/i/testoxy.i,v
retrieving revision 1.1
diff -r1.1 testoxy.i
47c47
<       is_obj(a,[0,-5,10],1)!=-1 || is_obj(a,"oops")!=-1 || is_obj(a,9)!=-1 ||
---
>       is_obj(a,[0,-5,10],1)!=-1 || is_obj(a,"oops",1)!=-1 || is_obj(a,9,1)!=-1 ||


Fri Jul 09, 2010 3:06 pm
Profile YIM
Yorick Master

Joined: Sun Sep 26, 2004 10:33 am
Posts: 150
Location: Australia
Post 
thanks Thierry. I had the same issue but haven't had time to debug in the last days. That indeed solves it.


Thu Jul 15, 2010 8:06 pm
Profile WWW
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post 
Thanks, Francois and Thierry.

I just committed the fix, both Thierry's fix to testoxy.i, and the fix to yorick/oxy.c for the uninitialized variable in Y_is_obj that caused testoxy.i to work correctly for me, while failing for Francois.

Eternal vigilance...

Please keep the bug reports coming in.


Sat Jul 17, 2010 2:48 pm
Profile
Yorick Guru

Joined: Thu May 10, 2007 12:07 pm
Posts: 62
Post 
Nice ! Very nice. It opens a lot of new possibilities.

I am wondering about one thing: is it wanted that obj("x") and obj.x have not the same behavior when the member "x" does not exists ? e.g.:

Code:
> obj = save()
> obj.x
[]
> obj("x")
ERROR (*main*) unable to get member x
WARNING source code unavailable (try dbdis function)
now at pc= 1 (of 12), failed at pc= 5
To enter debug mode, type <RETURN> now (then dbexit to get out)
>

From my point of view I would prefer that both return a void value instead of an error as when you type an empty symbol in yorick. (Sure it still can be tested with obj(-,"x") ).


--------------------------------------
Optional Reading :)
-------------------------------------
Did you plan to make users able to change the behavior of evaluation (e.g.: obj(args)) or the member extraction with the "." operator (e.g. obj.member) by a yorick user function ?

It would be great if one can define the member extraction (and the evaluator) like as follow:
Code:
func get_my_member (member) {
 
  indexes = use(-, "indexes") ? use("indexes") : [];
  if (!use(-,"data")) error, "data not defined";

  if (use("data")(-, noop(member)) return use("data")(noop(member))(indexes);
 
  return Whatever_is_suitable_for_a_non_member;
}
obj = save(data=save(x=random(10), y=random(10), indexes=1:10);
gmember, obj, get_my_member;

where gmember would be a built in function that cause get_my_member to be executed. e.i.:
Code:
obj = save( get=get_my_member, data=save(x=random(10), y=random(10), indexes=1:10));
gmember, obj, get_my_member;
obj.x
/* would be equivalent to */
obj( get, "x");


I am agree that it can be confusing and one can make infinity loop easily, plus one need a dedicated built in function to get the member of object without calling the user evaluator function (e.g. gget(obj,"x") ).
I can feel that you will not like to do that :)


Wed Sep 08, 2010 1:50 pm
Profile
Yorick Guru

Joined: Thu May 10, 2007 12:07 pm
Posts: 62
Post 
Bug or feature ? :

Code:
> func test(void) { info, use(); return 0;}
> a = save(test)
> a(test)
[]
> a(test)()
[]
0
> a(test, )
object with 1 members:
   test = func test(void)
0


It seems that when you do not explicitly add a void argument use() return a void object inside the function test.
[/code]


Thu Sep 09, 2010 11:13 am
Profile
Yorick Master

Joined: Wed Jun 01, 2005 11:34 am
Posts: 112
Post 
I believe that's a feature. From the documentation under "help, oxy":

Code:
When you pass more than one argument to an object, the first one
specifies a single member, and subsequent arguments apply to that
member.  Thus,
  obj(m, i, j, k)    is similar to     obj(m)(i, j, k)
In fact, these are exactly the same as long as M does not specify
a function. When M is a function, there is a slight difference,
which is that the function (whether built-in or interpreted) is
executed in the context of the object obj.


So of your three test cases, only the third called "test" using the object's context. Specifically:

a(test) -- calls test as a subroutine without context

a(test)() -- calls test as a function without context

a(test,) -- calls test as a function with context

To add a few more cases:

a.test -- calls test as a subroutine without context

a.test() -- calls test as a function without context

a, test -- calls test as a subroutine with context


Fri Sep 10, 2010 6:32 am
Profile
Yorick Guru

Joined: Thu May 10, 2007 12:07 pm
Posts: 62
Post 
Hum, okay, but, from the yorick-user-point-of-view, does it makes sense that
"a, test" is called with context and "a(test)" without context ?
Naturally, without thinking to much (that my way), I would believe that both are called with context one as subroutine the other as function.


Mon Sep 13, 2010 7:22 am
Profile
Yorick Master

Joined: Wed Jun 01, 2005 11:34 am
Posts: 112
Post 
I think it makes sense. "a(test)" asks Yorick to retrieve the value for "test" in "a". In this case, it's a function reference. Then, since you put that function reference on a line by itself without any functional arguments, it gets evaluated as a subroutine. Perhaps it'd help to consider that it's effectively equivalent to the following:
Code:
> tmp = a(test)
> tmp

Once you've pulled the value for "test" outside of the object, it no longer has its context.

If "a(test)" called test as a function, then you'd have no way to just retrieve the value for "test".


Mon Sep 13, 2010 9:30 am
Profile
Yorick Guru

Joined: Thu May 10, 2007 12:07 pm
Posts: 62
Post 
When there is a cyclic reference, the info function cause an infinite loop :

Code:
master = save( parent=[] );
save, master ,  child=save( parent=master );
info, master;


Tue Sep 14, 2010 2:21 pm
Profile
Yorick Master

Joined: Wed Jun 01, 2005 11:34 am
Posts: 112
Post 
According to these two links, cyclic references are not supported by Yorick's memory management model:

http://yorick.sourceforge.net/yorickfaq.php#Q29
http://yorick.sourceforge.net/phpBB2/vi ... ?p=640#640

So you may need to approach the problem without the bidirectional relationships to avoid memory leaks.


Wed Sep 15, 2010 1:14 pm
Profile
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post 
DNagle's answers are correct for the most part. Cyclic references are never correct in yorick; there is no way to delete them because yorick uses reference counting, not garbage collection. That's a feature, not a bug. So you need to design your data structures (of all kinds, not just objects -- it's easy to create a ring of pointers that fails for the same reason) so that they are trees, not rings. This is a pretty minor design requirement, I think, but you do need to be aware of it.

Let me try to clarify what goes wrong with both obj(method)(args) and obj.method(args). In both cases, if you disassemble the virtual machine code (with the disassemble function), you will see that the Eval or GetMember call happens before any of the args are even pushed onto the stack. Thus, the interpreter has no idea what you are going to DO with the method member. Furthermore, the method function, which is the return value of the Eval or GetMember action, has no idea that it "belongs" to the obj object -- in fact, it will usually be a member of many different object instances. Hence, by the time the args are being pushed onto the stack, let alone by the time of the Eval action corresponding to the final close parenthesis, the interpreter has completely forgotten that the method was extracted from obj. Thus it is not possible even in principle for those syntaxes to yield a call to method in the context of obj.

Eventually, I would like to change the parser to make x.m(args) produce exactly the same virtual machine code as x("m",args). At that point, the object.method(args) syntax will work properly, that is, it will work the same as in C++ or Java. That syntax will always be slightly less efficient than object(method,args), however, because the lookup of the string "method" is deferred to runtime in the former case, while the parser does the lookup in the latter case. So I encourage you to get used to the current syntax.

I'm not sure that I understand the get_my_member feature request in the 08/Sep sguieu post. I think the API can already do what you want, just in a slightly different way.


Mon Sep 20, 2010 7:15 pm
Profile
Yorick Guru

Joined: Thu May 10, 2007 12:07 pm
Posts: 62
Post 
Would it be more logic that when an oxy object is called with a void argument it return a copy of the object instead of the object itself ?
Code:
> g = save(a=1, b=2)
> g() == g
1
> g(1:0) == g
0

I do not see any cases where this behavior can be useful but it had, for me, a bit of confusion.

Sure one can still do:
Code:
g( (is_void(member) ? 1:0 : member) )


[/code]


Thu Feb 03, 2011 2:51 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 13 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.