Discussion:
[jifty-devel] Difference Between alias and import_templates in Template::Declare
David E. Wheeler
2009-10-07 04:27:13 UTC
Permalink
Howdy,

Other than the ability to set "package variables" in aliases, I've
found one other difference between aliases and imported templates: The
invocant.

In imported templates, the invocant is an object blessed into the
class into which the templates were imported.

In aliased templates, the invocant is an object blessed into the class
from which the templates were aliased.

Is this an important distinction? The tests in t/aliasing.t and t/
importing.t demonstrate it quite clearly, but I'm wondering whether
anyone ever noticed this or if it's necessary? To me, the behavior of
aliases is a bit weird, since they're supposed to be like mixins.

Thanks,

David
David E. Wheeler
2009-10-07 05:05:27 UTC
Permalink
Post by David E. Wheeler
In imported templates, the invocant is an object blessed into the
class into which the templates were imported.
In aliased templates, the invocant is an object blessed into the class
from which the templates were aliased.
Turns out that in neither case is an object passed. It looks like an
object is *never* passed. It's a class name. This, to me, makes the
distinction even less important.
Post by David E. Wheeler
Is this an important distinction? The tests in t/aliasing.t and t/
importing.t demonstrate it quite clearly, but I'm wondering whether
anyone ever noticed this or if it's necessary? To me, the behavior of
aliases is a bit weird, since they're supposed to be like mixins.
The questions still stand, though.

Best,

David
David E. Wheeler
2009-10-07 18:24:25 UTC
Permalink
Post by David E. Wheeler
Post by David E. Wheeler
In imported templates, the invocant is an object blessed into the
class into which the templates were imported.
In aliased templates, the invocant is an object blessed into the class
from which the templates were aliased.
Turns out that in neither case is an object passed. It looks like an
object is *never* passed. It's a class name. This, to me, makes the
distinction even less important.
It turns out that I was wrong to start with. The truth is that the
invocant is always the class from which the template was imported/
aliased. The only subtlety is when mixing in or aliasing a subclass of
templates:

* When importing a subclass of templates, the invocant is always the
class in which each template was defined.

* When aliasing a subclass of templates, the invocant is always the
subclass, regardless of whether a particular template was defined in
the subclass or a parent.

This is a pretty minor difference, but I've updated the tests in the
mixmaster branch to confirm this (the tests were ambiguous before). Is
there any reason for this inconsistency, does any code rely on it, or
was it just an oversight of the implementation?

Best,

David
David E. Wheeler
2009-10-07 18:55:10 UTC
Permalink
Post by David E. Wheeler
This is a pretty minor difference, but I've updated the tests in the
mixmaster branch to confirm this (the tests were ambiguous before). Is
there any reason for this inconsistency, does any code rely on it, or
was it just an oversight of the implementation?
I'm pretty sure that this was an oversight. I've changed the behavior
in r7520 in the mixmaster branch. More on that branch in a future post.

David
Jesse Vincent
2009-10-08 19:47:25 UTC
Permalink
Post by David E. Wheeler
Post by David E. Wheeler
Post by David E. Wheeler
In imported templates, the invocant is an object blessed into the
class into which the templates were imported.
In aliased templates, the invocant is an object blessed into the class
from which the templates were aliased.
Turns out that in neither case is an object passed. It looks like an
object is *never* passed. It's a class name. This, to me, makes the
distinction even less important.
It turns out that I was wrong to start with. The truth is that the
invocant is always the class from which the template was imported/
aliased. The only subtlety is when mixing in or aliasing a subclass of
* When importing a subclass of templates, the invocant is always the
class in which each template was defined.
* When aliasing a subclass of templates, the invocant is always the
subclass, regardless of whether a particular template was defined in
the subclass or a parent.
This is a pretty minor difference, but I've updated the tests in the
mixmaster branch to confirm this (the tests were ambiguous before). Is
there any reason for this inconsistency, does any code rely on it, or
was it just an oversight of the implementation?
It's a small, but not minor difference, as it changed how things work in
use cases involving inheritance. I remember a design session with clkao
where we hashed out the need for both and wrote the skeleton of the
tests to demonstrate it. What I don't remember is the actual use cases.
I'd really like to not break the old API, but I'd be happy to ship a
release with import_into Carp::cluck'ing with a message asking the user
to report the use case back to jifty-devel so we can doc how it was used
and find a newer, cleaner way to do what it did.

Does that seem like a reasonable way forward?

Best,
Jesse
David E. Wheeler
2009-10-09 00:17:36 UTC
Permalink
Post by Jesse Vincent
It's a small, but not minor difference, as it changed how things work in
use cases involving inheritance. I remember a design session with clkao
where we hashed out the need for both and wrote the skeleton of the
tests to demonstrate it. What I don't remember is the actual use cases.
I'd really like to not break the old API, but I'd be happy to ship a
release with import_into Carp::cluck'ing with a message asking the user
to report the use case back to jifty-devel so we can doc how it was used
and find a newer, cleaner way to do what it did.
It's actually `alias` that has the difference, and only when you alias
a class that inherits templates from a parent class. I could find a
place to carp about that case, yes.
Post by Jesse Vincent
Does that seem like a reasonable way forward?
Works for me, yes.

Best,

David
David E. Wheeler
2009-10-10 02:20:30 UTC
Permalink
Post by David E. Wheeler
It's actually `alias` that has the difference, and only when you alias
a class that inherits templates from a parent class. I could find a
place to carp about that case, yes.
Post by Jesse Vincent
Does that seem like a reasonable way forward?
Works for me, yes.
Looking more closely, I don't think it's possible to identify when the
user will get one thing but expect the other. Let me see if I can
explain with a very simple example.

Template class Foo defines template "hello".

Template class Foo::Bar inherits from Foo.

Template class Wifty::UI aliases Foo::Bar under /bar.

So what this means is that Wifty::UI has the template /bar/hello.

Now, everything is nearly the same as it was before: the code in the
"hello" template can access package variables (if any were set) via `
$self->get_package_variable`.

The *only* difference is that $self is now "Foo", whereas before it
would have been "Foo::Bar". This has no effect on the package
variables that can be fetched.

The only way in which I can imagine that this would bit a user is if
they were expecting Foo::Bar. Maybe Foo::Bar had another class method
that they would want access to. That makes no sense to me, though,
because the "hello" template is defined in the Foo class, and
therefore should have no knowledge of its subclasses. Maybe Foo::Bar
overrode a method defined in Foo. That might lead to something
unexpected. But I have a hard time believing that anyone would have
done this, not least because these are classes with class attributes,
not objects. So there isn't really much in the way of state.

So, the only way I could put in a cluck would be when someone did
something with the class name passed to the template. The overwhelming
majority of the time, such use would be legitimate. There is no way
for me to tell, in the code, that the user was expecting "Foo::Bar"
but got "Foo".

Make sense? Sorry to be a bit long-winded; I was honestly trying to
keep it simple. :-)

All that said, I could, with a bit of added complexity, restore the
passing of Foo::Bar to the hello template defined in Foo, but as I've
said, I can't really imagine that this wasn't a mistake, given its
inconsistency compared to `import_templates` and lack of any real
reason for it being so that I can ascertain.

Sorry, there I go again…

Best,

David
David E. Wheeler
2009-10-10 04:58:39 UTC
Permalink
Post by David E. Wheeler
Maybe Foo::Bar
overrode a method defined in Foo. That might lead to something
unexpected. But I have a hard time believing that anyone would have
done this, not least because these are classes with class attributes,
not objects. So there isn't really much in the way of state.
Shawn found one regression against my branch in the Jifty tests, and
it appears that this is exactly the case being tested. Here's one of
Post by David E. Wheeler
not ok 12 - found content '/base/list=TestApp::View::instance/
instance/view=TestApp::View::instance/instance/
view=TestApp::View::instance'
# Failed test 'found content '/base/list=TestApp::View::instance/
instance/view=TestApp::View::instance/instance/
view=TestApp::View::instance''
# at t/TestApp/t/15-template-subclass.t line 73.
# searched: "/base/list=TestApp::View::base/base/
view=TestApp::"...
# can't find: "/base/list=TestApp::View::instance/instance/
view=T"...
ok 13 - get 'http://localhost:11379: /jifty/jifty/trunk/t/TestApp/t/
15-template-subclass.t /instance/list_ht'
In these tests, TestApp::View::instance subclasses
TestApp::View::base. The templates in the latter output

outs("/base/list=$self");

So it fails because, with my changes, $self is ::base instead
of ::instance. That just demonstrates the point, and at first I just
assumed that the tests could perhaps be changed. However, looking at
the template classes, I see that both ::base and ::instance implement
a base_path() method. ::instance overrides its the implementation in
base. Therefor, when the base templates call

show($self->base_path.'/view');

it's relying on getting the value for the method returned by the
implementation in ::instance. So this does seem to be the the one way
I could see that the existing behavior might have been correct.

So it leads me to wonder: Could it be that the behavior of
`import_templates`, which always passes in the class in which a method
is defined, could be wrong? I'm wondering now whether, if I changed it
so that `import_methods` works like `alias` in this way, would there
be other regressions?

In other words, what happens if I make `import_temlates` consistent
with `alias` instead of the other way around, with respect to the
class name passed to the template? Do you think that would make more
sense?

Thanks,

David
David E. Wheeler
2009-10-10 05:08:17 UTC
Permalink
Post by David E. Wheeler
In other words, what happens if I make `import_temlates` consistent
with `alias` instead of the other way around, with respect to the
class name passed to the template? Do you think that would make more
sense?
I've done this in r7534. Interested to see what happens.

Best,

David
Shawn M Moore
2009-10-13 18:36:46 UTC
Permalink
Hi David,
Post by David E. Wheeler
Template class Foo defines template "hello".
Template class Foo::Bar inherits from Foo.
Template class Wifty::UI aliases Foo::Bar under /bar.
So what this means is that Wifty::UI has the template /bar/hello.
Now, everything is nearly the same as it was before: the code in the
"hello" template can access package variables (if any were set) via `
$self->get_package_variable`.
The *only* difference is that $self is now "Foo", whereas before it
would have been "Foo::Bar". This has no effect on the package
variables that can be fetched.
The only way in which I can imagine that this would bit a user is if
they were expecting Foo::Bar. Maybe Foo::Bar had another class method
that they would want access to. That makes no sense to me, though,
because the "hello" template is defined in the Foo class, and
therefore should have no knowledge of its subclasses. Maybe Foo::Bar
overrode a method defined in Foo. That might lead to something
unexpected. But I have a hard time believing that anyone would have
done this, not least because these are classes with class attributes,
not objects. So there isn't really much in the way of state.
I just want to point out that this is an important use case for us. We
do use the object-oriented features of Template::Declare and it is
important that they continue to work.

The most prevalent use of TD's OO is in Jifty's CRUD builder. Basically,
the CRUD builder is set up like:

sub record_class { ... }

sub display_columns { $self->record_class->... }
sub edit_columns { $self->record_class->... }

template 'view_item' => sub { ... }
template 'edit_item' => sub { ... }

I don't think we instantiate an object. We just make use of the
indirection of OO to let users subclass the CRUD builder to customize
it. They can, for example, change which columns are editable by
overriding the edit_columns method.
Post by David E. Wheeler
The *only* difference is that $self is now "Foo", whereas before it
would have been "Foo::Bar". This has no effect on the package
variables that can be fetched.
We also typically use "alias" to nail particular CRUD classes into the
template tree, so this is kind of a showstopper. :)

As I understand it, you have since fixed this, but I felt you deserved a
good explanation as to why we pass in the particular class we do.

Shawn
David E. Wheeler
2009-10-13 20:37:12 UTC
Permalink
Post by Shawn M Moore
I just want to point out that this is an important use case for us. We
do use the object-oriented features of Template::Declare and it is
important that they continue to work.
Thanks Shawn. Based on your testing results, I changed things around.
The behavior of `alias` is now as it was before, and
`import_templates` is different.
Post by Shawn M Moore
The most prevalent use of TD's OO is in Jifty's CRUD builder.
Basically,
sub record_class { ... }
sub display_columns { $self->record_class->... }
sub edit_columns { $self->record_class->... }
template 'view_item' => sub { ... }
template 'edit_item' => sub { ... }
I don't think we instantiate an object. We just make use of the
indirection of OO to let users subclass the CRUD builder to customize
it. They can, for example, change which columns are editable by
overriding the edit_columns method.
Yep. And now `import_templates` works with that, too. Previously, it
always passed the class in which each template was defined, but now it
passes in the class that the template is imported from, even if the
template is inherited by that class.
Post by Shawn M Moore
We also typically use "alias" to nail particular CRUD classes into the
template tree, so this is kind of a showstopper. :)
Yep, no more.
Post by Shawn M Moore
As I understand it, you have since fixed this, but I felt you
deserved a
good explanation as to why we pass in the particular class we do.
Yes, I appreciate it.

Before we decided to merge this stuff into trunk there were two things
I wanted to get nailed down:

* Improved documentation for this stuff. I'm now working on this and
should commit it later today.

* Discuss if the `alias` behavior really *is* what we want. I ask
because, in a real mixin system, the invocant passed to a mixed-in
method would be an object of the class into which it's mixed, not the
class from which it's mixed. Based on your comments here, I think that
the answer is yes, but I did want to reality-check it. Sound about
right?

Thanks,

David
Shawn M Moore
2009-10-13 21:06:40 UTC
Permalink
Post by David E. Wheeler
Post by Shawn M Moore
I just want to point out that this is an important use case for us. We
do use the object-oriented features of Template::Declare and it is
important that they continue to work.
Thanks Shawn. Based on your testing results, I changed things around.
The behavior of `alias` is now as it was before, and
`import_templates` is different.
Aye, cool. :)
Post by David E. Wheeler
Post by Shawn M Moore
As I understand it, you have since fixed this, but I felt you deserved a
good explanation as to why we pass in the particular class we do.
Yes, I appreciate it.
Before we decided to merge this stuff into trunk there were two things
* Improved documentation for this stuff. I'm now working on this and
should commit it later today.
Yay!
Post by David E. Wheeler
* Discuss if the `alias` behavior really *is* what we want. I ask
because, in a real mixin system, the invocant passed to a mixed-in
method would be an object of the class into which it's mixed, not the
class from which it's mixed. Based on your comments here, I think that
the answer is yes, but I did want to reality-check it. Sound about
right?
Perhaps mixin is the wrong metaphor for alias. I think delegation is a
better metaphor, since we really need the original class passed to the
aliased templates. See also
http://search.cpan.org/~drolsky/Moose-0.92/lib/Moose/Manual/Delegation.pod
for a definition of delegation and why it's good.

There's a place for the mixin metaphor, maybe that can be "import", or
something new.
Post by David E. Wheeler
Thanks,
David
Shawn
David E. Wheeler
2009-10-14 00:04:14 UTC
Permalink
Post by Shawn M Moore
Perhaps mixin is the wrong metaphor for alias. I think delegation is a
better metaphor, since we really need the original class passed to the
aliased templates. See also
http://search.cpan.org/~drolsky/Moose-0.92/lib/Moose/Manual/Delegation.pod
for a definition of delegation and why it's good.
Yes, delegation definitely better describes what it's doing, vis-a-vis
dispatch. I was using the mixin metaphor (and the `mix` method) based
on what I'd found in the docs so far.
Post by Shawn M Moore
There's a place for the mixin metaphor, maybe that can be "import", or
something new.
Well, `import` does something else in Perl. And it's not really an
import, either (which would be more like a mixin).

Honestly, though, I think `mix` is still the best work to use for the
feature because I can't think of a good way to make it happen with a
delegation metaphor. Delegation usually identifies all of the methods
to dispatch to when you specify it, as in:

use Class::Delegator
send => [qw(play pause rewind fast_forward shuffle)],
to => 'ipod';

Which is not exactly how the TD feature works. What we're doing is
mixing templates from one class into another class. The fact that the
first argument is the mixed-in class rather than the target class is
something that's easy to document and understandable.

So if it's okay with you and everyone else, I think I'd like to stick
with `mix`. Unless you all prefer the original `alias` method. I'd be
fine with that. Then it'd just be `import_templates` that'd be
deprecated.

Best,

David
David E. Wheeler
2009-10-14 00:46:08 UTC
Permalink
Post by David E. Wheeler
So if it's okay with you and everyone else, I think I'd like to stick
with `mix`. Unless you all prefer the original `alias` method. I'd be
fine with that. Then it'd just be `import_templates` that'd be
deprecated.
`include` might be another option. So, the examples:

mix Some::Clever::Mixin under '/mixin';
mix Some::Other::Mixin under '/otmix', setting { name =>
'Larry' };
mix My::Mixin into My::View, under '/mymix';

alias Some::Clever::Mixin under '/alias';
alias Some::Other::Mixin under '/otalias', setting { name
=> 'Larry' };
alias My::Mixin in My::View, under '/myalias';

include Some::Clever::Mixin under '/included';
include Some::Other::Mixin under '/otincluded', setting
{ name => 'Larry' };
include My::Mixin in My::View, under '/myincluded';

I think I still prefer `mix`: it's shortest, easy to explain, and can
use `into` instead of `in` for the class into which it mixes.

Best,

David
Shawn M Moore
2009-10-14 18:05:46 UTC
Permalink
Post by David E. Wheeler
Post by Shawn M Moore
Perhaps mixin is the wrong metaphor for alias. I think delegation is a
better metaphor, since we really need the original class passed to the
aliased templates. See also
http://search.cpan.org/~drolsky/Moose-0.92/lib/Moose/Manual/Delegation.pod
for a definition of delegation and why it's good.
Yes, delegation definitely better describes what it's doing, vis-a-vis
dispatch. I was using the mixin metaphor (and the `mix` method) based
on what I'd found in the docs so far.
The old TD docs.. let's just say it's probably okay if we burn them. :)
Post by David E. Wheeler
Post by Shawn M Moore
There's a place for the mixin metaphor, maybe that can be "import", or
something new.
Well, `import` does something else in Perl. And it's not really an
import, either (which would be more like a mixin).
Yes, agreed. I'm saying that we could have another separate feature that
covers mixin/import.
Post by David E. Wheeler
Honestly, though, I think `mix` is still the best work to use for the
feature because I can't think of a good way to make it happen with a
delegation metaphor. Delegation usually identifies all of the methods
use Class::Delegator
send => [qw(play pause rewind fast_forward shuffle)],
to => 'ipod';
The identification doesn't have to be done explicitly by the programmer.
For example, in Moose, we have:

has datetime => (
is => 'ro',
isa => 'DateTime',
handles => qr/.*/,
);

In TD, we similarly select all templates.
Post by David E. Wheeler
Which is not exactly how the TD feature works. What we're doing is
mixing templates from one class into another class. The fact that the
first argument is the mixed-in class rather than the target class is
something that's easy to document and understandable.
I'd rather not conflate the two.

Say we have a class C that mixes in a mixin M and has an attribute D. C
delegates some methods to D. The methods provided by mixin M will get C
as the invocant. The methods that are delegated to D will get D as the
invocant. There's a context switch involved with delegation that isn't
present with mixins.

The distinction is important. I'd really prefer to avoid clashing with
established models. If we get it right we can just say "oh if you use
this it's like a mixin, but if you use that it's like delegation." If we
get it wrong then users and experts alike will bang their heads against
it.

Both forms of composition are useful and good. I think we can have
both in TD.
Post by David E. Wheeler
Best,
David
Shawn
David E. Wheeler
2009-10-14 18:15:54 UTC
Permalink
Post by Shawn M Moore
The old TD docs.. let's just say it's probably okay if we burn
them. :)
Heh. That's rather where I started with this. Jesse offered me the
commit bit when I offered to submit doc patches.
Post by Shawn M Moore
Yes, agreed. I'm saying that we could have another separate feature that
covers mixin/import.
Hrm.
Post by Shawn M Moore
The identification doesn't have to be done explicitly by the
programmer.
has datetime => (
is => 'ro',
isa => 'DateTime',
handles => qr/.*/,
);
In TD, we similarly select all templates.
Well, no. With your example, you have to be explicit. With the current
implementation it's implicit. You can't name which templates to
delegate to. Not to say that that isn't a good idea, though…
Post by Shawn M Moore
I'd rather not conflate the two.
Say we have a class C that mixes in a mixin M and has an attribute D. C
delegates some methods to D. The methods provided by mixin M will get C
as the invocant. The methods that are delegated to D will get D as the
invocant. There's a context switch involved with delegation that isn't
present with mixins.
Agreed. There isn't currently a pure mixin model in T::D.
Post by Shawn M Moore
The distinction is important. I'd really prefer to avoid clashing with
established models. If we get it right we can just say "oh if you use
this it's like a mixin, but if you use that it's like delegation." If we
get it wrong then users and experts alike will bang their heads against
it.
Fair enough.
Post by Shawn M Moore
Both forms of composition are useful and good. I think we can have
both in TD.
Okay. Then the question then becomes, what should we call the current
delegation method?

delegate_to Some::Class in This::Class under '/foo' setting { foo
=> 'bar' };

I'd like a shorter expression than "delegate_to" (one reason I really
liked `mix`), but maybe I'm just being obtuse.

Comments?

Best,

David
Shawn M Moore
2009-10-14 18:38:15 UTC
Permalink
Post by David E. Wheeler
Post by Shawn M Moore
The old TD docs.. let's just say it's probably okay if we burn them. :)
Heh. That's rather where I started with this. Jesse offered me the
commit bit when I offered to submit doc patches.
Sorry, I mean the ancient docs Jesse wrote, not what you are
writing. To be fair to Jesse though, we're spending a lot more time on
fine details, and have the benefit of a lot of experience with using TD.
Post by David E. Wheeler
Post by Shawn M Moore
Yes, agreed. I'm saying that we could have another separate feature that
covers mixin/import.
Hrm.
Post by Shawn M Moore
The identification doesn't have to be done explicitly by the
programmer.
has datetime => (
is => 'ro',
isa => 'DateTime',
handles => qr/.*/,
);
In TD, we similarly select all templates.
Well, no. With your example, you have to be explicit. With the current
implementation it's implicit. You can't name which templates to
delegate to. Not to say that that isn't a good idea, though?
Sure, I just mean the programmer doesn't have to type the template names
mutiple times. I'm not sure that selecting which templates to delegate
to would be a useful feature. If it turns out we ever need it, we can add
it. It'll be easier than it would have been thanks to your refactoring. :)
Post by David E. Wheeler
Post by Shawn M Moore
I'd rather not conflate the two.
Say we have a class C that mixes in a mixin M and has an attribute D. C
delegates some methods to D. The methods provided by mixin M will get C
as the invocant. The methods that are delegated to D will get D as the
invocant. There's a context switch involved with delegation that isn't
present with mixins.
Agreed. There isn't currently a pure mixin model in T::D.
Post by Shawn M Moore
The distinction is important. I'd really prefer to avoid clashing with
established models. If we get it right we can just say "oh if you use
this it's like a mixin, but if you use that it's like delegation." If we
get it wrong then users and experts alike will bang their heads against
it.
Fair enough.
Post by Shawn M Moore
Both forms of composition are useful and good. I think we can have
both in TD.
Okay. Then the question then becomes, what should we call the current
delegation method?
delegate_to Some::Class in This::Class under '/foo' setting { foo
=> 'bar' };
I'd like a shorter expression than "delegate_to" (one reason I really
liked `mix`), but maybe I'm just being obtuse.
Hmm. I'd like to avoid the underscore if we can. Maybe just "delegate"
or even "alias".

delegate Some::Class in This::Class under '/foo' setting { foo => 'bar' };

delegate Some::Class under '/foo';

shrug!
Post by David E. Wheeler
Comments?
Best,
David
Shawn
David E. Wheeler
2009-10-14 19:44:02 UTC
Permalink
Post by Shawn M Moore
Sorry, I mean the ancient docs Jesse wrote, not what you are
writing. To be fair to Jesse though, we're spending a lot more time on
fine details, and have the benefit of a lot of experience with using TD.
Yeah, I didn't think you meant the stuff I'd written. Maybe it's time
to take out the "Bugs crawling all over" bit, though.
Post by Shawn M Moore
Sure, I just mean the programmer doesn't have to type the template names
mutiple times. I'm not sure that selecting which templates to delegate
to would be a useful feature. If it turns out we ever need it, we can add
it. It'll be easier than it would have been thanks to your
refactoring. :)
Agreed.
Post by Shawn M Moore
Hmm. I'd like to avoid the underscore if we can. Maybe just "delegate"
or even "alias".
delegate Some::Class in This::Class under '/foo' setting { foo => 'bar' };
delegate Some::Class under '/foo';
I'm happy not to have the underline, but I'm not sure "delegate" works
without the "to". But maybe it doesn't matter?

David
Ruslan Zakirov
2009-10-14 19:45:36 UTC
Permalink
On Wed, Oct 14, 2009 at 10:38 PM, Shawn M Moore
[snip]
Post by Shawn M Moore
Post by David E. Wheeler
Post by Shawn M Moore
Both forms of composition are useful and good. I think we can have
both in TD.
Okay. Then the question then becomes, what should we call the current
delegation method?
   delegate_to Some::Class in This::Class under '/foo' setting { foo
=> 'bar' };
I'd like a shorter expression than "delegate_to" (one reason I really
liked `mix`), but maybe I'm just being obtuse.
Hmm. I'd like to avoid the underscore if we can. Maybe just "delegate"
or even "alias".
delegate Some::Class in This::Class under '/foo' setting { foo => 'bar' };
delegate Some::Class under '/foo';
delegate to Some::Class in This::Class under '/foo' setting { foo => 'bar' };

delegate '/foo' in This::Class to Some::Class setting {};
Post by Shawn M Moore
shrug!
Post by David E. Wheeler
Comments?
Best,
David
Shawn
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
--
Best regards, Ruslan.
Shawn M Moore
2009-10-14 19:48:36 UTC
Permalink
Post by Ruslan Zakirov
delegate to Some::Class in This::Class under '/foo' setting { foo => 'bar' };
This could work.
Post by Ruslan Zakirov
delegate '/foo' in This::Class to Some::Class setting {};
This would be confusing. I'd think it was taking the /foo template in
This::Class and putting it into Some::Class.

Shawn
Ruslan Zakirov
2009-10-14 19:58:18 UTC
Permalink
On Wed, Oct 14, 2009 at 11:48 PM, Shawn M Moore
Post by Shawn M Moore
Post by Ruslan Zakirov
delegate to Some::Class in This::Class under '/foo' setting { foo => 'bar' };
This could work.
Post by Ruslan Zakirov
delegate '/foo' in This::Class to  Some::Class setting {};
This would be confusing. I'd think it was taking the /foo template in
This::Class and putting it into Some::Class.
Actually I like this more as it shows path first and it's correct
english as far as I know :)
Post by Shawn M Moore
Shawn
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
--
Best regards, Ruslan.
David E. Wheeler
2009-10-14 20:37:55 UTC
Permalink
Post by Shawn M Moore
Post by Ruslan Zakirov
delegate '/foo' in This::Class to Some::Class setting {};
This would be confusing. I'd think it was taking the /foo template in
This::Class and putting it into Some::Class.
Yeah, that was my problem with it. I started with

send '/foo' in This::Class to Some::Class, setting {};

I don't think you could do it without more commas, though. It is
better English, but it's a little weird syntactically.

Best,

David
David E. Wheeler
2009-10-15 01:47:59 UTC
Permalink
Post by Shawn M Moore
Post by Ruslan Zakirov
delegate '/foo' in This::Class to Some::Class setting {};
This would be confusing. I'd think it was taking the /foo template in
This::Class and putting it into Some::Class.
Thanks to this discussion and some chatter on IRC, I realized that the
old `import_templates` interface was the mixin interface, and the
`alias` method was the delegation interface.

So now I've un-deprecated `alias` and will document it as the
delegation interface. And I've changed `mix` and the still-deprecated
`import_templates` so that they now have the class into which they are
imported be the invocant.

So what this means, in the end, is that the code is now different from
when I started in the following ways:

* `alias` now creates much more efficient aliases, and supports an
`into` parameter
* `mix` is the new name for `import_templates` and also supports an
`into` parameter
* `mix` and `alias` can now both be called with package variables
assigned, optionally via the `setting` keyword.
* `import_templates` is deprecated but works the same as always.

In short, I've added some new features, simplified the code, but have
not broken compatibility in any way that I know of.

Best,

David

Loading...