Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-27 Thread Rob Kinyon
On 10/26/05, Larry Wall [EMAIL PROTECTED] wrote:
 On Wed, Oct 26, 2005 at 07:35:05PM -0700, chromatic wrote:
 : On Wed, 2005-10-26 at 21:58 -0400, Rob Kinyon wrote:
 :
 :  Plus, the argument is a straw man. Instead of:
 : 
 :  class Some::Class is also {
 :  }
 : 
 :  you would do:
 : 
 :  class My::Version {
 :  does Some::Class;
 :  }
 : 
 :  Problem solved.
 :
 : Don't forget the fun of modifying all existing uses of Some::Class to
 : use My::Version instead, if that's even possible.

 That should mostly be handled by virtualized class names.

Will I be able to do something like:

package Foo;
$*VERSION = 1.3.2;

use Foo-1.3.1;

role My::Foo { does Foo; ... }
alias My::Foo - Foo; # Or whatever the syntax should be

And, in my other code, use Foo; will DWIM?


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-27 Thread Larry Wall
On Thu, Oct 27, 2005 at 05:37:13AM -0400, Rob Kinyon wrote:
: Will I be able to do something like:
: 
: package Foo;

Hmm, you just started in Perl 5 mode.

: $*VERSION = 1.3.2;

Perl 5 would get confused here, so I'm presuming Perl 6.  But Perl 6
isn't likely to let you override the global run-time Perl version.

: use Foo-1.3.1;

That I think I understand.

: role My::Foo { does Foo; ... }

Okay, My::Foo does Foo here.  Presumably it must do the Foo alias
that the use just installed.  And presumably the Foo you just used
is a role that can be done.  Certainly you can't do the global
package Foo, assuming that's what your original package declared.

: alias My::Foo - Foo; # Or whatever the syntax should be

I have no clue where you're intending to install that alias.
Are you trying to install a *Foo alias?  A bare Foo is going to first
find the local alias to the Foo you used, and that hides the global
Foo that it would have found otherwise.  I suspect you're trying to
say

*Foo := My::Foo;

: And, in my other code, use Foo; will DWIM?

I don't know quite what you mean, so I don't know if it'll do what
you mean.  If you're trying to establish a policy that defaults a
particular name to a particular version, the library interface will
probably give you a more straightforward way to set that up.

Larry


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-27 Thread Rob Kinyon
On 10/27/05, Larry Wall [EMAIL PROTECTED] wrote:
 On Thu, Oct 27, 2005 at 05:37:13AM -0400, Rob Kinyon wrote:
 : Will I be able to do something like:
 :
 : package Foo;

 Hmm, you just started in Perl 5 mode.

 : $*VERSION = 1.3.2;

 Perl 5 would get confused here, so I'm presuming Perl 6.  But Perl 6
 isn't likely to let you override the global run-time Perl version.

 : use Foo-1.3.1;

 That I think I understand.

 : role My::Foo { does Foo; ... }

 Okay, My::Foo does Foo here.  Presumably it must do the Foo alias
 that the use just installed.  And presumably the Foo you just used
 is a role that can be done.  Certainly you can't do the global
 package Foo, assuming that's what your original package declared.

 : alias My::Foo - Foo; # Or whatever the syntax should be

 I have no clue where you're intending to install that alias.
 Are you trying to install a *Foo alias?  A bare Foo is going to first
 find the local alias to the Foo you used, and that hides the global
 Foo that it would have found otherwise.  I suspect you're trying to
 say

 *Foo := My::Foo;

 : And, in my other code, use Foo; will DWIM?

 I don't know quite what you mean, so I don't know if it'll do what
 you mean.  If you're trying to establish a policy that defaults a
 particular name to a particular version, the library interface will
 probably give you a more straightforward way to set that up.

Sorry. I'm not up on the syntax. I should do some serious backlog reading.

What I'm trying to do is load role Foo 1.0, have My::Foo do Foo, then
call My::Foo version 2.0 of Foo so that anyone else in my program will
see My::Foo instead of the original Foo. Is this possible?

Rob


Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Rob Kinyon
 : 3) Aren't classes mutable and roles immutable by default only? Or has
 : this changed?

 Of course.  To change the default for a role, call it a class, and
 to change the default for a class, call it a role.  :-)

Does this mean that roles are the recommended way to create immutable
classes? Given that roles and classes now seem to differ only in their
mutability, I can't see a reason why I would use class as my default
object definer. I would prefer to use roles as they're closed by
default, leaving class to be my powertool, if I need the power.

Rob


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread chromatic
On Wed, 2005-10-26 at 20:29 -0400, Rob Kinyon wrote:

 I would prefer to use roles as they're closed by default, leaving
 class to be my powertool, if I need the power.

I don't understand this desire; can you explain your reasoning?

(NB: closed here, as I use it, still *does not* correspond to
licensing or availability of the source code.)

-- c



Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Rob Kinyon
On 10/26/05, chromatic [EMAIL PROTECTED] wrote:
 On Wed, 2005-10-26 at 20:29 -0400, Rob Kinyon wrote:

  I would prefer to use roles as they're closed by default, leaving
  class to be my powertool, if I need the power.

 I don't understand this desire; can you explain your reasoning?

If a role is an immutable class, that means that its internals cannot
be changed. Hence, the compiler can trust that it will be the same at
the end as at the beginning. Which means it's optimized. Which means
my objects run faster if I create them from roles than if I create
them from classes. And, given that this seems to be the sole
difference between them (mutability vs. immutability), why would I use
classes as my standard?

Rob


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Luke Palmer
On 10/26/05, Rob Kinyon [EMAIL PROTECTED] wrote:
 On 10/26/05, chromatic [EMAIL PROTECTED] wrote:
  On Wed, 2005-10-26 at 20:29 -0400, Rob Kinyon wrote:
 
   I would prefer to use roles as they're closed by default, leaving
   class to be my powertool, if I need the power.
 
  I don't understand this desire; can you explain your reasoning?

 If a role is an immutable class, that means that its internals cannot
 be changed. Hence, the compiler can trust that it will be the same at
 the end as at the beginning. Which means it's optimized. Which means
 my objects run faster if I create them from roles than if I create
 them from classes. And, given that this seems to be the sole
 difference between them (mutability vs. immutability), why would I use
 classes as my standard?

Okay, an open class means you can add methods to it, right?  So, let's
say you have this class:

class Foo {
method foo() {...}
method bar() {...}
}

And this code:

my Foo $x = Foo.new;
$x.foo();
$x.bar();

This might be compiled to the following pseudo intermediate code:

my $x = Foo[0]();
Foo[1]($x);
Foo[2]($x);

Now let's say you extend the class:

   class Foo is also {
   method baz() {...}
   }

Is there any reason that the preceding pseudo intermediate code is no
longer valid?  I don't see one; baz() is just installed in slot 3.  So
why would you say it was faster to have it closed?

Indeed, it *could* be faster.  But we find that many programmers make
decisions that trade readability and extensibility for an extra 1% of
speed, even when they are writing a command-line frontend to
MPlayer[1].  If those people are module writers, then we have a bunch
of modules on CPAN that are not friendly to the user who wants to use
the module in the one way the writer didn't expect.

So the reason we made classes open by default is so that people
wouldn't have a chance to make that decision until they're more
experienced.  Indeed, no module writer can say that a class is closed;
only the main program may say that, because the main program knows the
most about how everything is used.  The precise definition of main
program is not well-defined yet, but it's there so that a module
writer doesn't close himself off from the world without knowing how
his module is even being used.

And if you're going to use roles for everything because they're closed
and they will gain you 2% of speed on one particular backend, then
we'll have to make the same rule for them too.  I know it sounds like
we're babying our programmers.  We are, because it's such a
widespread superstition.

And just to reinforce that it's a superstition:  a theory defines a
vtable.  If you extend the class in an incompatible way, you have to
make a new instance of its theory, defining new vtable slots.  Once
the new vtable is created, it is just as fast as the old one.  There
is no speed loss whatsoever for keeping your class open.

Luke

[1] This is a concrete example that I actually witnessed.


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Larry Wall
On Wed, Oct 26, 2005 at 08:48:12PM -0400, Rob Kinyon wrote:
: If a role is an immutable class, that means that its internals cannot
: be changed. Hence, the compiler can trust that it will be the same at
: the end as at the beginning. Which means it's optimized. Which means
: my objects run faster if I create them from roles than if I create
: them from classes. And, given that this seems to be the sole
: difference between them (mutability vs. immutability), why would I use
: classes as my standard?

Because it might be a premature optimization to the extent that it
restricts flexibility before you know whether it's going to affect
performance.  Part of the power of Ruby on Rails reputedly comes from
the fact that Ruby leaves its classes open by default.

Larry


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread chromatic
On Wed, 2005-10-26 at 19:22 -0600, Luke Palmer wrote:

 But we find that many programmers make decisions that trade
 readability and extensibility for an extra 1% of speed, even when they
 are writing a command-line frontend to MPlayer[1].  If those people
 are module writers, then we have a bunch of modules on CPAN that are
 not friendly to the user who wants to use the module in the one way
 the writer didn't expect.

Worse, that's a *theoretical* 1% of speed based on non-profiled code.

 And if you're going to use roles for everything because they're closed
 and they will gain you 2% of speed on one particular backend, then
 we'll have to make the same rule for them too.  I know it sounds like
 we're babying our programmers.  We are, because it's such a
 widespread superstition.

I prefer to think of it as Helping to prevent them from writing
unreusable code.

 And just to reinforce that it's a superstition:  a theory defines a
 vtable.  If you extend the class in an incompatible way, you have to
 make a new instance of its theory, defining new vtable slots.  Once
 the new vtable is created, it is just as fast as the old one.  There
 is no speed loss whatsoever for keeping your class open.

Even further, don't forget that someone, somewhere will really need to
do something you didn't think of.  Either he extends your class somehow
or works around it in an ugly, funky way.

Which one is faster to write?  Which one is faster to execute?  Which
one is more likely to be correct?  Which one is more maintainable?

-- c



Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Rob Kinyon
On 10/26/05, Luke Palmer [EMAIL PROTECTED] wrote:
[snip]
 Okay, an open class means you can add methods to it, right?  So, let's
 say you have this class:

 class Foo {
 method foo() {...}
 method bar() {...}
 }

 And this code:

 my Foo $x = Foo.new;
 $x.foo();
 $x.bar();

 This might be compiled to the following pseudo intermediate code:

 my $x = Foo[0]();
 Foo[1]($x);
 Foo[2]($x);

 Now let's say you extend the class:

class Foo is also {
method baz() {...}
}

 Is there any reason that the preceding pseudo intermediate code is no
 longer valid?  I don't see one; baz() is just installed in slot 3.  So
 why would you say it was faster to have it closed?

What about:

class Foo is also {
method foo() { ... }
}

Where the second foo() is no longer what the first foo() did.
Furthermore, let's say you have:

class Bar isa Foo {
method floober() { ... }
}

If they were roles, then role Bar could alias all the methods it
inherits from role Foo. In other words, it can cache all the method
lookups at compile-time. That's a substantial savings. If they're open
classes, the runtime has to throw out all the cached lookups the
moment any of the classes upstream are modified.

Plus, the argument is a straw man. Instead of:

class Some::Class is also {
}

you would do:

class My::Version {
does Some::Class;
}

Problem solved.

Rob


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread chromatic
On Wed, 2005-10-26 at 21:58 -0400, Rob Kinyon wrote:

 Plus, the argument is a straw man. Instead of:
 
 class Some::Class is also {
 }
 
 you would do:
 
 class My::Version {
 does Some::Class;
 }
 
 Problem solved.

Don't forget the fun of modifying all existing uses of Some::Class to
use My::Version instead, if that's even possible.

-- c



Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Larry Wall
On Wed, Oct 26, 2005 at 07:35:05PM -0700, chromatic wrote:
: On Wed, 2005-10-26 at 21:58 -0400, Rob Kinyon wrote:
: 
:  Plus, the argument is a straw man. Instead of:
:  
:  class Some::Class is also {
:  }
:  
:  you would do:
:  
:  class My::Version {
:  does Some::Class;
:  }
:  
:  Problem solved.
: 
: Don't forget the fun of modifying all existing uses of Some::Class to
: use My::Version instead, if that's even possible.

That should mostly be handled by virtualized class names.

Larry


Re: Roles vs. Classes (was Re: Ways to add behavior)

2005-10-26 Thread Luke Palmer
On 10/26/05, Rob Kinyon [EMAIL PROTECTED] wrote:
 What about:

 class Foo is also {
 method foo() { ... }
 }

 Where the second foo() is no longer what the first foo() did.

Just overwrite the vtable.

 Furthermore, let's say you have:

 class Bar isa Foo {
 method floober() { ... }
 }

 If they were roles, then role Bar could alias all the methods it
 inherits from role Foo. In other words, it can cache all the method
 lookups at compile-time. That's a substantial savings. If they're open
 classes, the runtime has to throw out all the cached lookups the
 moment any of the classes upstream are modified.

This one is a little better.  It is expensive to rejig all the cached
methods, but that expense comes at the time when you reopen.  If you
never reopen, you never pay a penalty.

 Plus, the argument is a straw man. Instead of:

 class Some::Class is also {
 }

 you would do:

 class My::Version {
 does Some::Class;
 }

 Problem solved.

Unless your module is the one creating the Some::Classes, or unless
(as you point out above) there are existing subclasses of Some::Class,
or unless some other thing that you didn't think of, which is the
whole point of this discussion.  There is no omniscient library
writer; there is no omniscient language designer.  :-)

Luke