Class with user defined fields or properties
11 posts
• Page 1 of 2 • 1, 2
Class with user defined fields or properties
I want to confirm something I think is true:
There is no way to have a user-defined name/value stuffed into a class, that the class itself can know about. That is if I have an instance T of a class, and I do:
There is no way for a public or private method of T to see MyMadeUpName.
Is this correct?
There is no way to have a user-defined name/value stuffed into a class, that the class itself can know about. That is if I have an instance T of a class, and I do:
T.MyMadeUpName←7
There is no way for a public or private method of T to see MyMadeUpName.
Is this correct?
- paulmansour
- Posts: 420
- Joined: Fri Oct 03, 2008 4:14 pm
Re: Class with user defined fields or properties
I recently found a way to do this but wasn't sure if it was a bug, so reported it to Dyalog but they are still investigating.
From an instance of a class I use the dyadic execute to access the attached namespace like this:
From an instance of a class I use the dyadic execute to access the attached namespace like this:
⍝ external access from instance
∇r←ListExternal
:Access Public Instance
r←⎕THIS ⍎'⎕NL 2'
∇
∇name SetExternal value
:Access Public Instance
name(⎕THIS{⍺⍺⍎⍺'←⍵'})value
∇
- gil
- Posts: 71
- Joined: Mon Feb 15, 2010 12:42 am
Re: Class with user defined fields or properties
Oh boy, that probably is generating some internal discussion!
The reason I ask this is that I am pondering a data structure for name/value pairs (similar to a k dictionary), and considering a simple namespace, with external functions that operate on it, verses a class with methods. I want direct, non quoted dot access to the names, and since we don't know what they are ahead of time, cannot use public fields or properties.
The latter would only work with the trick you note above, which seems a bit dodgy. I'm leaning towards a simple namespace.
The reason I ask this is that I am pondering a data structure for name/value pairs (similar to a k dictionary), and considering a simple namespace, with external functions that operate on it, verses a class with methods. I want direct, non quoted dot access to the names, and since we don't know what they are ahead of time, cannot use public fields or properties.
The latter would only work with the trick you note above, which seems a bit dodgy. I'm leaning towards a simple namespace.
- paulmansour
- Posts: 420
- Joined: Fri Oct 03, 2008 4:14 pm
Re: Class with user defined fields or properties
For what it's worth, I also settled for a normal namespace with external functions. I was experimenting with a thin layer to deal with objects shared with JavaScript where some keys are invalid apl names. Using a keyed default property I can mimic JavaScript's syntax:
While still being able to use it as a normal namespace.
Being able to access those external names was key to be able to serialize it, but it just got too awkward compared to a solution using a couple of external functions.
I'm still curious to hear what Dyalog makes of my findings. As you say, it is hard to explain the difference in behaviour between using execute monadically.
ns['$exists' 'name']←(⊂'true')'Gil'
While still being able to use it as a normal namespace.
ns.name←'Gilgamesh'
Being able to access those external names was key to be able to serialize it, but it just got too awkward compared to a solution using a couple of external functions.
I'm still curious to hear what Dyalog makes of my findings. As you say, it is hard to explain the difference in behaviour between using execute monadically.
- gil
- Posts: 71
- Joined: Mon Feb 15, 2010 12:42 am
Re: Class with user defined fields or properties
The following is taken from a document I've been working on which will (hopefully) be the basis of some future documentation.
Names in the Dyalog OO Model.
"Grey Boxes" and Symbol Tables
A namespace in Dyalog APL includes a list of symbols (AKA names). We refer to this list of symbols as a “Symbol Table”.
In order to provide encapsulation of symbols in the Dyalog OO model, an instance of a class is implemented as a single namespace with multiple symbol tables. There is a single symbol table for each level in the instance’s class hierarchy. At Dyalog we sometimes refer these symbol tables as "grey boxes" (as per diagrams that have been drawn for internal use over the years). In addition, there is a symbol table that is not associated with any base class. This symbol table is used to store arbitrary names from outside the class hierarchy. Previous documents referred to this symbol table as the “APL Execution Space”, internally we sometimes refer to it as the "white box". Typically, symbols in a box are visible to code that is defined by the same class, and are not visible (i.e. are "private") to code defined in other boxes (:Access public makes a symbol visible across boxes)
Consider then a class A, and an instance a
:class A
:field Private first←'john'
∇r←get_first
:access public
r←first
∇
:endclass
a←⎕new A
The name "first" in the class is private. Expected OO behaviour means that "first" is hidden from the outside world:
a.first
VALUE ERROR
But also that a should behave as if A.first does not exist. This means that
a.first←'andy'
Should work. And indeed, it does, because this assignment creates a symbol "first" in a different "box" (i.e. a different symbol table) to the one that the class code is operating in.
a.first is a different symbol to the "first" symbol that get_first has access to.
The Dyalog interpreter switches between symbol tables at appropriate times, for example, we switch to the grey box associated with "A", when get_first is called. Generally, the APL programmer has no way to switch boxes other than by calling code defined in the relevant class.
The APL Execute primitive, ⍎
Monadic execute executes an expression in the current namespace, by extension it executes the expression in the current "grey box" (i.e. with access to the current symbol table). So, if we had:
⍎'first'
Inside get_first then, the result would be 'john'.
Dyadic execute however, executes the expression in the space provided by the left argument. There is no way to specify the "grey box" in which the expression should be executed, so it is done in the "white box" for the space, so the result will be 'andy'.
Note also, that other "dotted" uses of ⎕THIS (and ⎕BASE) are more aware of the "grey boxes". For example, from within get_first:
⍎'first'
john
⎕this ⍎'first'
andy
⎕this.⍎'first'
john
Names in the Dyalog OO Model.
"Grey Boxes" and Symbol Tables
A namespace in Dyalog APL includes a list of symbols (AKA names). We refer to this list of symbols as a “Symbol Table”.
In order to provide encapsulation of symbols in the Dyalog OO model, an instance of a class is implemented as a single namespace with multiple symbol tables. There is a single symbol table for each level in the instance’s class hierarchy. At Dyalog we sometimes refer these symbol tables as "grey boxes" (as per diagrams that have been drawn for internal use over the years). In addition, there is a symbol table that is not associated with any base class. This symbol table is used to store arbitrary names from outside the class hierarchy. Previous documents referred to this symbol table as the “APL Execution Space”, internally we sometimes refer to it as the "white box". Typically, symbols in a box are visible to code that is defined by the same class, and are not visible (i.e. are "private") to code defined in other boxes (:Access public makes a symbol visible across boxes)
Consider then a class A, and an instance a
:class A
:field Private first←'john'
∇r←get_first
:access public
r←first
∇
:endclass
a←⎕new A
The name "first" in the class is private. Expected OO behaviour means that "first" is hidden from the outside world:
a.first
VALUE ERROR
But also that a should behave as if A.first does not exist. This means that
a.first←'andy'
Should work. And indeed, it does, because this assignment creates a symbol "first" in a different "box" (i.e. a different symbol table) to the one that the class code is operating in.
a.first is a different symbol to the "first" symbol that get_first has access to.
The Dyalog interpreter switches between symbol tables at appropriate times, for example, we switch to the grey box associated with "A", when get_first is called. Generally, the APL programmer has no way to switch boxes other than by calling code defined in the relevant class.
The APL Execute primitive, ⍎
Monadic execute executes an expression in the current namespace, by extension it executes the expression in the current "grey box" (i.e. with access to the current symbol table). So, if we had:
⍎'first'
Inside get_first then, the result would be 'john'.
Dyadic execute however, executes the expression in the space provided by the left argument. There is no way to specify the "grey box" in which the expression should be executed, so it is done in the "white box" for the space, so the result will be 'andy'.
Note also, that other "dotted" uses of ⎕THIS (and ⎕BASE) are more aware of the "grey boxes". For example, from within get_first:
⍎'first'
john
⎕this ⍎'first'
andy
⎕this.⍎'first'
john
-
JohnD|Dyalog - Posts: 74
- Joined: Wed Oct 01, 2008 9:35 am
Re: Class with user defined fields or properties
Thanks for the explanation John. I must admit that I thought the dyadic execute would be identical to monadic execute where the left argument is a reference and not a name (text string).
It doesn't sound like you are planning to change this behaviour. What is your recommendation? "Don't exploit this, we will probably change/fix this." or "This is the way to access the white box, we are documenting it for future reference."?
It doesn't sound like you are planning to change this behaviour. What is your recommendation? "Don't exploit this, we will probably change/fix this." or "This is the way to access the white box, we are documenting it for future reference."?
- gil
- Posts: 71
- Joined: Mon Feb 15, 2010 12:42 am
Re: Class with user defined fields or properties
John, thanks for the detailed explanation. I second Gil's question for recommendations. My gut feeling is that one should probably avoid looking at stuff in the white space from within the class, unless of course one is doing something special, which is what I was looking at doing.
I think it is all pretty clear, and if it is documented and not subject to change, it all looks good to me.
While is is a little confusing that ⎕This.⍎ is a different than ⎕This⍎, if it is made clear that the latter is essentially special syntax for entering the white space from within the instance, it is all clear. I assume that is a valid way to phrase it?
I think it is all pretty clear, and if it is documented and not subject to change, it all looks good to me.
While is is a little confusing that ⎕This.⍎ is a different than ⎕This⍎, if it is made clear that the latter is essentially special syntax for entering the white space from within the instance, it is all clear. I assume that is a valid way to phrase it?
- paulmansour
- Posts: 420
- Joined: Fri Oct 03, 2008 4:14 pm
Re: Class with user defined fields or properties
I don't think it is correct to describe (⎕THIS⍎expr) as some kind of work-around that allows you to access the white box. Dyadic ⍎ is supposed to view an object "from the outside", and run the expression "in the white box". I would argue that this does not need special documentation, or a "guarantee" that it won't stop working.
On the contrary, it is the the "ref.expr" syntax that is providing special behaviour when the ref points to a grey box that you are already in. In this case, instead of doing the "normal" thing and giving you the outside / white box / view of the object, the DOT decides you probably want to stay where you are and runs the expression using monadic ⍎ in the current box. "⎕BASE." is even more special syntax, which allows you to invoke an overridden method of a base class.
If I were to argue for a change in behaviour, I think it would be that (⎕THIS.expression) should ALSO run in the white box.
On the contrary, it is the the "ref.expr" syntax that is providing special behaviour when the ref points to a grey box that you are already in. In this case, instead of doing the "normal" thing and giving you the outside / white box / view of the object, the DOT decides you probably want to stay where you are and runs the expression using monadic ⍎ in the current box. "⎕BASE." is even more special syntax, which allows you to invoke an overridden method of a base class.
If I were to argue for a change in behaviour, I think it would be that (⎕THIS.expression) should ALSO run in the white box.
-
Morten|Dyalog - Posts: 454
- Joined: Tue Sep 09, 2008 3:52 pm
Re: Class with user defined fields or properties
Having slept on this, I think it is correct to say that "⎕BASE." also presents an outside view of the base class, only giving access to public names from it. So it is only "⎕THIS." that is a special case. I am not sure it is practical to change this now, but my feeling is that it would be more correct and more useful if that also gave you the white box view. You don't need the current behaviour of "⎕THIS.blah", you could just write "blah"?
-
Morten|Dyalog - Posts: 454
- Joined: Tue Sep 09, 2008 3:52 pm
11 posts
• Page 1 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 1 guest
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group