Real (trivial) mixins

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 | Next >

Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Just thought I'd put this out there, topic came up in #io today about  
real mixins (not utilizing differential inheritance), so I set out to  
write them and realized that, it's extremely trivial. 5 lines of well  
structured code, or one line of still readable code. I'll put it in  
the former just because. :) It's presented below:

Object asMixin := method(
     self slotNames foreach(name,
         call sender setSlot(name, self getSlot(name))
     )
)

Enjoy.

Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


I suppose a use case would be apropos. It'll be very bad, but design  
isn't what this is about.

Consider the utility object "Math" containing an "add" method which,  
ironically enough, adds two numbers together.

Math := Object clone do(
     add := method(n, m, n + m)
)

Consider another object Foo, which mixes in this object:

Foo := Object clone do(
     Math asMixin
)

Now, we can run:

Foo add(2, 3) // yields 5

Then, if we replace Math's add method, with this:

Math add := method(n, m, n * m)

And run Foo add(2, 3) again, we'll notice it still returns 5, while  
Math add(2, 3) returns 6 (since it's now doing multiplication instead  
of addition).

On 15-Apr-09, at 12:40 PM, Jeremy Tregunna wrote:

> Just thought I'd put this out there, topic came up in #io today about
> real mixins (not utilizing differential inheritance), so I set out to
> write them and realized that, it's extremely trivial. 5 lines of well
> structured code, or one line of still readable code. I'll put it in
> the former just because. :) It's presented below:
>
> Object asMixin := method(
>     self slotNames foreach(name,
>         call sender setSlot(name, self getSlot(name))
>     )
> )
>
> Enjoy.
>
> Regards,
>
> Jeremy Tregunna
> jeremy.tregunna@...
>
>
>
>
>
> ------------------------------------
>
> Yahoo! Groups Links
>
>
>

Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by Guy Hulbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, 2009-15-04 at 12:43 -0400, Jeremy Tregunna wrote:
> And run Foo add(2, 3) again, we'll notice it still returns 5, while
> Math add(2, 3) returns 6 (since it's now doing multiplication instead
> of addition).

Hmm.. can you explain a bit more -- *why* you would want to do this.
It's useful to know that this is how Io behaves but it's not obvious to
me why it's useful.  There must be some "real world" example.

Also, could you easily change the mixin design so that the change to
Math would automatically propagate to Foo?  I think it would be easy but
I have not yet managed to collect enough tuits to start learning Io.

tq

--
--gh



Re: Real (trivial) mixins

by Samuel A. Falvo II :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Apr 15, 2009 at 9:55 AM, Guy Hulbert <gwhulbert@...> wrote:
> Hmm.. can you explain a bit more -- *why* you would want to do this.

Isolation.  Use this method when/if you anticipate your parent(s)
might change in the future, but you want to preserve their current
behavior as a snapshot now.

> It's useful to know that this is how Io behaves but it's not obvious to
> me why it's useful.  There must be some "real world" example.

I would suggest studying CLU or Sather and how they use mixins for
program composition.  That will explain things far more effectively
than executive and potentially contrived examples here.

> Also, could you easily change the mixin design so that the change to
> Math would automatically propagate to Foo?

Simply clone Math, but do not invoke asMixin.

--
Samuel A. Falvo II

Re: Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 15-Apr-09, at 1:04 PM, Samuel A. Falvo II wrote:

> On Wed, Apr 15, 2009 at 9:55 AM, Guy Hulbert <gwhulbert@...> wrote:
>> Also, could you easily change the mixin design so that the change to
>> Math would automatically propagate to Foo?
>
> Simply clone Math, but do not invoke asMixin.

An example:

Foo := Object clone do(prependProto(Math); ...)

Foo add(2, 3) == 5 // before replacing Math add
Foo add(2, 3) == 6 // after replacing Math add with the multiplication  
example earlier

Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by spir :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Le Wed, 15 Apr 2009 10:04:38 -0700,
"Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:

> > Hmm.. can you explain a bit more -- *why* you would want to do this.  
>
> Isolation.  Use this method when/if you anticipate your parent(s)
> might change in the future, but you want to preserve their current
> behavior as a snapshot now.

I would rather ask the opposite question: in which (real world and/or theoretical) case can one expect the parent methods to change *and* wish this change to propagate to clones?

Denis
------
la vita e estrany

Re: Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 15-Apr-09, at 1:29 PM, spir wrote:

> Le Wed, 15 Apr 2009 10:04:38 -0700,
> "Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:
>
>>> Hmm.. can you explain a bit more -- *why* you would want to do this.
>>
>> Isolation.  Use this method when/if you anticipate your parent(s)
>> might change in the future, but you want to preserve their current
>> behavior as a snapshot now.
>
> I would rather ask the opposite question: in which (real world and/
> or theoretical) case can one expect the parent methods to change  
> *and* wish this change to propagate to clones?

Consider you're modeling a new drug, and some element changes in it.  
Would you not want that change to reflect against all instances  
thereof in your model?

Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by Samuel A. Falvo II :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Apr 15, 2009 at 10:29 AM, spir <denis.spir@...> wrote:
> I would rather ask the opposite question: in which (real world and/or theoretical) case can one expect the parent methods to change *and* wish this change to propagate to clones?

I'm not sure why you're asking me this.

This line of questioning is ultimately meaningless in a fully dynamic,
prototypical model as Io, precisely because you ultimately have no
control over whether or not it happens.  It would make more sense in a
language with statically delineated interfaces that, once the
compilation unit is done with, remains static throughout the rest of
the runtime.

Consider if you're writing an application in Io, and you find two
libraries (one written by me, one by Jeremy), which individually you
find very useful in your work.

You obviously have no express intent on tweaking Math.  But suppose
both my library and Jeremy's tweaks Math in some individually useful,
but mutually exclusive, way as a private means of implementation.
Presumably, YOUR code depends on Math's default behavior; you're
unaware that either of our libraries tweaks Math without looking at
the source code.

What do you do?  What do we do?

Obviously, the best solution is for both of us to clone Math, convert
them to a mixin, then tweak as appropriate.  That way, our individual
changes remain private to our respective libraries, without altering
the public environment your code depends on.

You might say, "But wait!  You can just rely on Io's differential
inheritance to isolate your changes!"  Correct -- but it does NOT
isolate YOUR changes from our expectations of Math.  If you alter Math
directly, then our libraries' understanding of Math's interface might
change in an incompatible way.

Again, this is a horribly contrived example, and is certainly not
idiomatic.  This is why I asked for those interested to investigate
how CLU and/or Sather utilized mixins because their literature is more
mature on the subject.

--
Samuel A. Falvo II

Re: Real (trivial) mixins

by Guy Hulbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, 2009-15-04 at 10:04 -0700, Samuel A. Falvo II wrote:
> > Also, could you easily change the mixin design so that the change to
> > Math would automatically propagate to Foo?
>
> Simply clone Math, but do not invoke asMixin.

Ah.  Easy.  Thanks (to everyone else as well).

--
--gh



Re: Real (trivial) mixins

by Dope Ice Apollyon the Third :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I think you're getting caught up in this detail of Io's behaviour.
Mixins are very useful for collecting a set of behaviour in one
package *that can be attached to types at will*. A favourite use of
mine is to quickly turn things into -like types (e.g. list-like or
dictionary-like types); in, say, Java you're stuck with rewriting all
the functionality yourself (even if you state that your type
"implements" a particular interface), while in python I can write a
mixin that provides sorting if you'll just define get(index) and
set(index) methods.

For a real world example: I just wrote a couple python mixins that
provide "name" and "description" functionality for classes in the
textadventure I'm writing. Respectively they pull out the class's name
and replace the underscores with spaces and titlecase the names, and
pull a default item description from the docstring but allow you to
override it (okay so maybe this last use is a bit contrived but I
didn't want to tie myself to docstrings unneccessarily). The typical
single-inheritence solution would be to make everything with
descriptions and names inherheit from one superclass, which usually
works for a while but webs you in more and more as the program gets
built.

If I changed the mixin I definitely would want everything that pulled
from it to get the change since the mixin behaviour belongs to the
mixin, it's just letting other things borrow. I must confess I've
never actually thought of trying to do this, though. What a curious
idea!

-Nick

On 15/04/2009, spir <denis.spir@...> wrote:

> Le Wed, 15 Apr 2009 10:04:38 -0700,
> "Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:
>
>> > Hmm.. can you explain a bit more -- *why* you would want to do this.
>>
>> Isolation.  Use this method when/if you anticipate your parent(s)
>> might change in the future, but you want to preserve their current
>> behavior as a snapshot now.
>
> I would rather ask the opposite question: in which (real world and/or
> theoretical) case can one expect the parent methods to change *and* wish
> this change to propagate to clones?
>
> Denis
> ------
> la vita e estrany
>

Re: Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What you're describing is an aspect. Note I didn't provide an  
asAspect, because that would make absolutely no sense in the context  
of the one liner i posted initially. Aspects definitely need to be  
updated if something changes, mixins do not usually. In the case where  
they may need to be, just continue as normal, no need to use the  
asMixin method I provided. To me, I look at mixins that mix in  
behaviour to a specific case, unlikely to have interdependencies to  
other mixins. If the latter is the case, then I think of them as  
aspects, and flip my brain to AOP style. But who knows, maybe that's  
just me.

On 15-Apr-09, at 2:07 PM, Nick Guenther wrote:

> I think you're getting caught up in this detail of Io's behaviour.
> Mixins are very useful for collecting a set of behaviour in one
> package *that can be attached to types at will*. A favourite use of
> mine is to quickly turn things into -like types (e.g. list-like or
> dictionary-like types); in, say, Java you're stuck with rewriting all
> the functionality yourself (even if you state that your type
> "implements" a particular interface), while in python I can write a
> mixin that provides sorting if you'll just define get(index) and
> set(index) methods.
>
> For a real world example: I just wrote a couple python mixins that
> provide "name" and "description" functionality for classes in the
> textadventure I'm writing. Respectively they pull out the class's name
> and replace the underscores with spaces and titlecase the names, and
> pull a default item description from the docstring but allow you to
> override it (okay so maybe this last use is a bit contrived but I
> didn't want to tie myself to docstrings unneccessarily). The typical
> single-inheritence solution would be to make everything with
> descriptions and names inherheit from one superclass, which usually
> works for a while but webs you in more and more as the program gets
> built.
>
> If I changed the mixin I definitely would want everything that pulled
> from it to get the change since the mixin behaviour belongs to the
> mixin, it's just letting other things borrow. I must confess I've
> never actually thought of trying to do this, though. What a curious
> idea!
>
> -Nick
>
> On 15/04/2009, spir <denis.spir@...> wrote:
>> Le Wed, 15 Apr 2009 10:04:38 -0700,
>> "Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:
>>
>>>> Hmm.. can you explain a bit more -- *why* you would want to do  
>>>> this.
>>>
>>> Isolation.  Use this method when/if you anticipate your parent(s)
>>> might change in the future, but you want to preserve their current
>>> behavior as a snapshot now.
>>
>> I would rather ask the opposite question: in which (real world and/or
>> theoretical) case can one expect the parent methods to change *and*  
>> wish
>> this change to propagate to clones?
>>
>> Denis
>> ------
>> la vita e estrany
>>

Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by Scott Solmonson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hmm perhaps I'm missing something-

Does not the standard Proto behavior already make this easy (and  
sensible?)
Why would I not just clone "Math" to "ScottMath", then create a  
modified-behavior "add" slot in ScottMath, and add ScottMath to the  
proto chain going forward?
So, all my "add" calls would hit ScottMath, and everything else that I  
didn't redefine would just roll up to Math?

--
Scott N Solmonson
408.718.6290




On Apr 15, 2009, at 11:07 AM, Nick Guenther wrote:

> I think you're getting caught up in this detail of Io's behaviour.
> Mixins are very useful for collecting a set of behaviour in one
> package *that can be attached to types at will*. A favourite use of
> mine is to quickly turn things into -like types (e.g. list-like or
> dictionary-like types); in, say, Java you're stuck with rewriting all
> the functionality yourself (even if you state that your type
> "implements" a particular interface), while in python I can write a
> mixin that provides sorting if you'll just define get(index) and
> set(index) methods.
>
> For a real world example: I just wrote a couple python mixins that
> provide "name" and "description" functionality for classes in the
> textadventure I'm writing. Respectively they pull out the class's name
> and replace the underscores with spaces and titlecase the names, and
> pull a default item description from the docstring but allow you to
> override it (okay so maybe this last use is a bit contrived but I
> didn't want to tie myself to docstrings unneccessarily). The typical
> single-inheritence solution would be to make everything with
> descriptions and names inherheit from one superclass, which usually
> works for a while but webs you in more and more as the program gets
> built.
>
> If I changed the mixin I definitely would want everything that pulled
> from it to get the change since the mixin behaviour belongs to the
> mixin, it's just letting other things borrow. I must confess I've
> never actually thought of trying to do this, though. What a curious
> idea!
>
> -Nick
>
> On 15/04/2009, spir <denis.spir@...> wrote:
>> Le Wed, 15 Apr 2009 10:04:38 -0700,
>> "Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:
>>
>>>> Hmm.. can you explain a bit more -- *why* you would want to do  
>>>> this.
>>>
>>> Isolation.  Use this method when/if you anticipate your parent(s)
>>> might change in the future, but you want to preserve their current
>>> behavior as a snapshot now.
>>
>> I would rather ask the opposite question: in which (real world and/or
>> theoretical) case can one expect the parent methods to change *and*  
>> wish
>> this change to propagate to clones?
>>
>> Denis
>> ------
>> la vita e estrany
>>
>
>
> ------------------------------------
>
> Yahoo! Groups Links
>
>
>


Re: Real (trivial) mixins

by Samuel A. Falvo II :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Apr 15, 2009 at 9:24 PM, Scott Solmonson <scosol@...> wrote:
> So, all my "add" calls would hit ScottMath, and everything else that I
> didn't redefine would just roll up to Math?

I already explained this in my hypothetical example.  What you're
describing here is great, as long as you can trust Math to never, ever
be tweaked by anyone else.

If I redefine Math minus to actually perform multiplication, then your
clone will inherit this errant behavior as well.

--
Samuel A. Falvo II

Re: Real (trivial) mixins

by spir :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Le Wed, 15 Apr 2009 22:38:23 -0700,
"Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:

> On Wed, Apr 15, 2009 at 9:24 PM, Scott Solmonson <scosol@...> wrote:
> > So, all my "add" calls would hit ScottMath, and everything else that I
> > didn't redefine would just roll up to Math?
>
> I already explained this in my hypothetical example.  What you're
> describing here is great, as long as you can trust Math to never, ever
> be tweaked by anyone else.
>
> If I redefine Math minus to actually perform multiplication, then your
> clone will inherit this errant behavior as well.
>

Just an addition to try and be clear. The point in Jeremy's asMixin is to first inherit behaviour from a proto, while beeing independant of its possible future evolution. We could call it "free inheritance", while the standard is "linked inheritance": if ever any method changes in the proto, these changes will affect the children as well.

I have a question on how Jeremy's method works:

Object asMixin := method(
     self slotNames foreach(name,
         call sender setSlot(name, self getSlot(name))
     )
)

As I understand it, the pseudo-clone gets a copy of the pseudo-proto's slot dictionary -- which is a set of named references to actual attribute objects. Right? So that additions and deletions on the proto won't affect the child. But what about changes on an already existing method? Is it possible to change a method while keeping its object ID (so that the child dict's reference would point to the modified method object)? Or on the contrary does a change on a method necessarily yield a brand new object with a different ID?

Denis
------
la vita e estrany

Re: Real (trivial) mixins

by Jeremy Tregunna-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 16-Apr-09, at 4:09 AM, spir wrote:

> Le Wed, 15 Apr 2009 22:38:23 -0700,
> "Samuel A. Falvo II" <sam.falvo@...> s'exprima ainsi:
>
>> On Wed, Apr 15, 2009 at 9:24 PM, Scott Solmonson  
>> <scosol@...> wrote:
>>> So, all my "add" calls would hit ScottMath, and everything else  
>>> that I
>>> didn't redefine would just roll up to Math?
>>
>> I already explained this in my hypothetical example.  What you're
>> describing here is great, as long as you can trust Math to never,  
>> ever
>> be tweaked by anyone else.
>>
>> If I redefine Math minus to actually perform multiplication, then  
>> your
>> clone will inherit this errant behavior as well.
>>
>
> Just an addition to try and be clear. The point in Jeremy's asMixin  
> is to first inherit behaviour from a proto, while beeing independant  
> of its possible future evolution. We could call it "free  
> inheritance", while the standard is "linked inheritance": if ever  
> any method changes in the proto, these changes will affect the  
> children as well.

Not exactly. You'll note in my second e-mail, that I create two  
objects that descend from Object. I mix in the behaviour of the first  
object into the second. Foo didn't inherit from Math directly, Math's  
state was mixed into its already existing object.

> I have a question on how Jeremy's method works:
>
> Object asMixin := method(
>     self slotNames foreach(name,
>         call sender setSlot(name, self getSlot(name))
>     )
> )
>
> As I understand it, the pseudo-clone gets a copy of the pseudo-
> proto's slot dictionary -- which is a set of named references to  
> actual attribute objects. Right?

Right.

> So that additions and deletions on the proto won't affect the child.  
> But what about changes on an already existing method? Is it possible  
> to change a method while keeping its object ID (so that the child  
> dict's reference would point to the modified method object)? Or on  
> the contrary does a change on a method necessarily yield a brand new  
> object with a different ID?

Correct me if I'm wrong, but I think what you're asking is something  
like this:

Math getSlot("add") foo := 42 // setting an attribute on the method
Foo getSlot("add") foo // returns the value 42
>


The reason this happens is because I'm not doing a deep copy of  
everything on Math into Foo, that's just very expensive and difficult  
to implement in Io. Instead, what I am doing, is storing a reference  
to the original object, so that for the common case (replacing a  
method with something else), you still have a reference to the  
original object, not the modified object that was put in its place on  
Math.

As a result, what ends up happening is your object id's are different  
if you replace Math add with some other implementation, comparing it  
to Foo add. Foo add always points to the original. But, if you modify  
Math add, so for instance, adding the "foo" slot to the actual method  
object, then Foo will also see that change. It's a way of hiding state  
that you can modify, passing it to descendants of the mixin and when  
you update it, have it change as well. Not necessarily a good thing,  
but I don't see it as a bad thing either since most people don't  
manipulate methods in this way (in fact, I think I'm the only one I  
know of that does, and only very rarely).

What would be more common than attaching an attribute onto a method,  
is to set Math add() to have a cached value. Consider it a lazy macro  
for the moment, upon its first execution it does some big expensive  
calculation, then modifies itself setting its cachedResult to the  
value it calculated, so subsequent calls, are made in O(1) time rather  
than some other time complexity, saving you cycles, since all it does  
is a fetch into memory, checks an offset in a structure, and if it's  
not the nil sentinel, return it and abort execution. So in the case  
where you do something like this:

Math add := method(n, m, r := n + m; self getSlot(call message name)  
setCachedResult(r); r)
Foo := Object clone do(Math asMixin);
Foo add(2, 3) // 6, actually went through the paces to get that value
Foo add(5, 10) // 6 still, because 6 was cached on the add object.  
Even though you're not doing this on Math, Math's implementation of  
add is doing it, which you're mixing it in.

Even if you were able to get the name of the receiver of a message,  
let's say you were for the moment, and you added that bit of logic to  
Math add() to check "If it's Math or a descendant of Math calling me,  
then set the cached result, otherwise, don't" then what happens in the  
above, is those two calls to add() on Foo, will yield 6 and 50  
respectively. However, if in the middle you add a: Math add(2, 3)  
it'll return 6, set the cachedResult on the method object, then the  
second call to add() on Foo will yield 6, instead of 50.

I hope this makes sense, as contrived as it is.

> Denis


Regards,

Jeremy Tregunna
jeremy.tregunna@...




Re: Real (trivial) mixins

by Guy Hulbert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 2009-16-04 at 08:09 -0400, Jeremy Tregunna wrote:
> The reason this happens is because I'm not doing a deep copy of
> everything on Math into Foo, that's just very expensive and difficult
> to implement in Io.

I think this answers the question I was originally trying to ask.

[snip]
> I hope this makes sense, as contrived as it is.

It makes sense to me.  It would be useful if it made it into the Io
documentation somewhere ... I've saved a copy in case I get enough tuits
to do something about it.

--
--gh



Re: Real (trivial) mixins

by spir :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Le Thu, 16 Apr 2009 08:09:20 -0400,
Jeremy Tregunna <jeremy.tregunna@...> s'exprima ainsi:


> > Just an addition to try and be clear. The point in Jeremy's asMixin  
> > is to first inherit behaviour from a proto, while beeing independant  
> > of its possible future evolution. We could call it "free  
> > inheritance", while the standard is "linked inheritance": if ever  
> > any method changes in the proto, these changes will affect the  
> > children as well.
>
> Not exactly. You'll note in my second e-mail, that I create two  
> objects that descend from Object. I mix in the behaviour of the first  
> object into the second. Foo didn't inherit from Math directly, Math's  
> state was mixed into its already existing object.

Yes. Thank you for the precision.

> > I have a question on how Jeremy's method works:
> >
> > Object asMixin := method(
> >     self slotNames foreach(name,
> >         call sender setSlot(name, self getSlot(name))
> >     )
> > )
> >
> > As I understand it, the pseudo-clone gets a copy of the pseudo-
> > proto's slot dictionary -- which is a set of named references to  
> > actual attribute objects. Right?
>
> Right.
>
> > So that additions and deletions on the proto won't affect the child.  
> > But what about changes on an already existing method? Is it possible  
> > to change a method while keeping its object ID (so that the child  
> > dict's reference would point to the modified method object)? Or on  
> > the contrary does a change on a method necessarily yield a brand new  
> > object with a different ID?
>
> Correct me if I'm wrong, but I think what you're asking is something  
> like this:
>
> Math getSlot("add") foo := 42 // setting an attribute on the method
> Foo getSlot("add") foo // returns the value 42

Exactly. That's it: I had no example in mind, but actually adding an attribute on a method is a kind of change that does not affect the method-object's ID (not sure of the correct terminology used in Io's community, but I guess 'ID' is clearly understood). So that the child, even if not cloned but "mixin-ed" instead, will see such changes.

> The reason this happens is because I'm not doing a deep copy of  
> everything on Math into Foo, that's just very expensive and difficult  
> to implement in Io. Instead, what I am doing, is storing a reference  
> to the original object, so that for the common case (replacing a  
> method with something else), you still have a reference to the  
> original object, not the modified object that was put in its place on  
> Math.

OK. So as a summary we have 4 types of method changes, not 3:
* deletion
* addition (new name)
* replacement (same name)
* "superficial" change (both name & ID unchanged)
The latter case only will propagate to mixin descendants.
Correct?

> As a result, what ends up happening is your object id's are different  
> if you replace Math add with some other implementation, comparing it  
> to Foo add. Foo add always points to the original. But, if you modify  
> Math add, so for instance, adding the "foo" slot to the actual method  
> object, then Foo will also see that change. It's a way of hiding state  
> that you can modify, passing it to descendants of the mixin and when  
> you update it, have it change as well. Not necessarily a good thing,  
> but I don't see it as a bad thing either since most people don't  
> manipulate methods in this way (in fact, I think I'm the only one I  
> know of that does, and only very rarely).

> What would be more common than attaching an attribute onto a method,  
> is to set Math add() to have a cached value. Consider it a lazy macro  
> for the moment, upon its first execution it does some big expensive  
> calculation, then modifies itself setting its cachedResult to the  
> value it calculated, so subsequent calls, are made in O(1) time rather  
> than some other time complexity, saving you cycles, since all it does  
> is a fetch into memory, checks an offset in a structure, and if it's  
> not the nil sentinel, return it and abort execution. So in the case  
> where you do something like this:
>
> Math add := method(n, m, r := n + m; self getSlot(call message name)  
> setCachedResult(r); r)
> Foo := Object clone do(Math asMixin);
> Foo add(2, 3) // 6, actually went through the paces to get that value
> Foo add(5, 10) // 6 still, because 6 was cached on the add object.  
> Even though you're not doing this on Math, Math's implementation of  
> add is doing it, which you're mixing it in.

Another use case: PEG parsing using packrat memoization (see wikipedia for info on these topics).
The packrat trick is, once a pattern has matched a source string at a specific position, the result for this (pattern + pos) pair is cached so that it needs not beeing checked again. While not wonderfully accelerating (as such cases can only happen for choices, the gain depends on the choice complexity of the grammar); this ensures a linear parse time (function of source length).
On a simple PEG parser, each 'pattern' can be represented by a func in code -- on which results could be cached in a dict of (pos:result) pairs.

[...]
> I hope this makes sense, as contrived as it is.

Sure.

> Jeremy Tregunna
> jeremy.tregunna@...

Denis
------
la vita e estrany

Re: Real (trivial) mixins

by spir :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Le Wed, 15 Apr 2009 12:40:07 -0400,
Jeremy Tregunna <jeremy.tregunna@...> s'exprima ainsi:

> Just thought I'd put this out there, topic came up in #io today about  
> real mixins (not utilizing differential inheritance), so I set out to  
> write them and realized that, it's extremely trivial. 5 lines of well  
> structured code, or one line of still readable code. I'll put it in  
> the former just because. :) It's presented below:
>
> Object asMixin := method(
>      self slotNames foreach(name,
>          call sender setSlot(name, self getSlot(name))
>      )
> )
>
> Enjoy.

One more general question.
Some time ago I evoked the possibility of copying a proto's dict to its clones, instead of having a method lookup chain (don't remember how I did it, but probably similar to the above).
An obvious advantage is the absence of method lookup along a sequence of protos, and its possible complicated issues (MRO): each object carries its own whole method dictionary. In fact, I had this solution in mind while trying to write a prototype simulation in python; couldn't find another (simple) way to implement "method sharing" at the object-level (instead of class).

Now, I wonder whether this could not be the standard way of sharing behaviour between clones of the same proto, in another hypothetical prototype-based language (instead the current way used in Io).
In the case discussed here, changes on the proto like deletion, addition or complete replacement of a method will not affect the clones. This is true between clones as well: they can evolve independently. Only superficial changes (that don't affect the method-object's ID), like changing an attribute on it, will be shared.
The basic language design should be different: in Io, 'Object' tends to hold all what its clones may ever need. On the contrary, a language in which objects have their own complete dict should make Object as light as possible and implement additional features on specialized "interface-carriers" intended to be mixed-in.
What do you think?

> Regards,
>
> Jeremy Tregunna
> jeremy.tregunna@...

Denis

------
la vita e estrany

Re: Real (trivial) mixins

by Steve Dekorte :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 2009-04-16, at 7:33 AM, spir wrote:
> The basic language design should be different: in Io, 'Object' tends  
> to hold all what its clones may ever need. On the contrary, a  
> language in which objects have their own complete dict should make  
> Object as light as possible and implement additional features on  
> specialized "interface-carriers" intended to be mixed-in. What do  
> you think?

That's basically how class based languages (and some prototype based  
languages like Self) work.

Some issues:
1. it's often useful to have inherited properties that you can change  
in one place instead of all instances
2. the model doesn't unify namespaces and objects

Re: Real (trivial) mixins

by spir :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Le Thu, 16 Apr 2009 15:47:46 -0700,
Steve Dekorte <steve@...> s'exprima ainsi:

>
> On 2009-04-16, at 7:33 AM, spir wrote:
> > The basic language design should be different: in Io, 'Object' tends  
> > to hold all what its clones may ever need. On the contrary, a  
> > language in which objects have their own complete dict should make  
> > Object as light as possible and implement additional features on  
> > specialized "interface-carriers" intended to be mixed-in. What do  
> > you think?
>
> That's basically how class based languages (and some prototype based  
> languages like Self) work.
>
> Some issues:
> 1. it's often useful to have inherited properties that you can change  
> in one place instead of all instances

Yes.

> 2. the model doesn't unify namespaces and objects

This I don't understand.

Denis
------
la vita e estrany
< Prev | 1 - 2 | Next >