[groovy-jsr] another try on groovy's features

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[groovy-jsr] another try on groovy's features

Jochen Theodorou
Hi,

maybe we should look at groovy with different eyes. Maybe we should cler
if we really want some of the features groovy has.

I will try to make some exmamples and each on can say if they want them
to have or not.

1a) overwriting of methods during runtime
using the use construct or DefaultGroovyMethods to overwrite a method of
an object. You could say the implementation is somehow exchanged.

1b) overwriting of methods during compile time
using the use construct or DefaultGroovyMethods to overwrite a method of
an object. You could say the implementation is somehow exchanged. The
decision which method is choosen for execution is done at compiletime.
For this decision the DefaultMetaClass is used. Unlike the dynamic case
1a) a use construct would not have any impact on already compiled code.
it would only influence the code within the use block and nested scopes.

2a) adding methods during runtime
the same mechanism as 1a, but without overwriting methods

2b) adding methods during compiletime
the same mechanism as 2a, but without overwriting methods

3a) smalltalk like missing-message fallback (dynamic)
if no suitable method is found during runtime call invokeMethod as long
as the object is an instance of GroovyObject

3a) smalltalk like missing-message fallback (static)
if no method is suitable call invokeMethod as long as the object is an
instance of GroovyObject. The decision time for this is compiletime.
This means the compiler has to know all possible methods so he can
decide to call invokeMethod instead of a missing method

4a) choose the method during runtime
4b) choose the method during compiletime


Think of the following program:

class A implements GroovyObject{
   def foo(Object s){1}
}

A a = getSubclassInstanceOfA()
assert a.foo("bar") == 1

even if all the points are true, we know there is a method A#foo(Object).
If 1*) is true, then we can't be sure the method A#foo(Object) is called
because it might be overwritten. Or I should say the call is redirected
to another method.
if 2*) is true, then we can't be sure the method A#foo(Object) is called
because it might be overloaded with a method foo(String) from a use
construct or default GroovyMethods
for 3*) should have no impact here
if 4b) should be true only the b side of 1-3 can be true. And if we
ignore 1-2 we can be sure A#foo(Object) is called.
for 4a) we can't be sure that A#foo(Object) is called since a subclass
could add a method foo(String) which is then used instead.

as you can see there is only one case (ignoring 3*) where we can be sure
that A#foo(Object) is called.

Another example:

class A implements GroovyObject{
}

A a = getSubclassInstanceOfA()
assert a.foo("bar") == 1

as you see we are calling a method that does not exist in A. Compiling
can fail if only the 1b and/or 2b are true. If none of 1-3 is true it
can't fail in case of 4a since a subclass may have added a method foo.
In case of 3a invokeMethod has to be called, a possible implementation
in a subclass would not be called. This means it is not really like a
missing method fall back in general, it's a fall back for missing
methods in the choosen class to make the method call on.

In case of groovy all a-cases are true.  This means a method can never
be selected at compile time. Practically even private methods are
allowed to be overwritten, or added through subclasses and others.

I look forward to hear some comments on these

bye blackdrag
Reply | Threaded
Open this post in threaded view
|

RE: [groovy-jsr] another try on groovy's features

Dierk König
I'd say that although implementation-vise Groovy adds methods at runtime,
there currently is no easy way for the application programmer to use
that feature.
In Ruby for example, I can do:
 class_eval("\ndef bla_mehod\n"+my_method_body+"\nend")}
which results in having bla_mehtod() added to my current class.
Doing the  same in Groovy would be really tricky.

So from an application programmers perspective, I think we can
forget about the scenario above in Groovy and go for adding
methods at compiletime.

only my 2 cents
Mittie


> -----Original Message-----
> From: Jochen Theodorou [mailto:[hidden email]]
> Sent: Freitag, 4. November 2005 22:01
> To: [hidden email]
> Subject: [groovy-jsr] another try on groovy's features
>
>
> Hi,
>
> maybe we should look at groovy with different eyes. Maybe we should cler
> if we really want some of the features groovy has.
>
> I will try to make some exmamples and each on can say if they want them
> to have or not.
>
> 1a) overwriting of methods during runtime
> using the use construct or DefaultGroovyMethods to overwrite a method of
> an object. You could say the implementation is somehow exchanged.
>
> 1b) overwriting of methods during compile time
> using the use construct or DefaultGroovyMethods to overwrite a method of
> an object. You could say the implementation is somehow exchanged. The
> decision which method is choosen for execution is done at compiletime.
> For this decision the DefaultMetaClass is used. Unlike the dynamic case
> 1a) a use construct would not have any impact on already compiled code.
> it would only influence the code within the use block and nested scopes.
>
> 2a) adding methods during runtime
> the same mechanism as 1a, but without overwriting methods
>
> 2b) adding methods during compiletime
> the same mechanism as 2a, but without overwriting methods
>
> 3a) smalltalk like missing-message fallback (dynamic)
> if no suitable method is found during runtime call invokeMethod as long
> as the object is an instance of GroovyObject
>
> 3a) smalltalk like missing-message fallback (static)
> if no method is suitable call invokeMethod as long as the object is an
> instance of GroovyObject. The decision time for this is compiletime.
> This means the compiler has to know all possible methods so he can
> decide to call invokeMethod instead of a missing method
>
> 4a) choose the method during runtime
> 4b) choose the method during compiletime
>
>
> Think of the following program:
>
> class A implements GroovyObject{
>    def foo(Object s){1}
> }
>
> A a = getSubclassInstanceOfA()
> assert a.foo("bar") == 1
>
> even if all the points are true, we know there is a method A#foo(Object).
> If 1*) is true, then we can't be sure the method A#foo(Object) is called
> because it might be overwritten. Or I should say the call is redirected
> to another method.
> if 2*) is true, then we can't be sure the method A#foo(Object) is called
> because it might be overloaded with a method foo(String) from a use
> construct or default GroovyMethods
> for 3*) should have no impact here
> if 4b) should be true only the b side of 1-3 can be true. And if we
> ignore 1-2 we can be sure A#foo(Object) is called.
> for 4a) we can't be sure that A#foo(Object) is called since a subclass
> could add a method foo(String) which is then used instead.
>
> as you can see there is only one case (ignoring 3*) where we can be sure
> that A#foo(Object) is called.
>
> Another example:
>
> class A implements GroovyObject{
> }
>
> A a = getSubclassInstanceOfA()
> assert a.foo("bar") == 1
>
> as you see we are calling a method that does not exist in A. Compiling
> can fail if only the 1b and/or 2b are true. If none of 1-3 is true it
> can't fail in case of 4a since a subclass may have added a method foo.
> In case of 3a invokeMethod has to be called, a possible implementation
> in a subclass would not be called. This means it is not really like a
> missing method fall back in general, it's a fall back for missing
> methods in the choosen class to make the method call on.
>
> In case of groovy all a-cases are true.  This means a method can never
> be selected at compile time. Practically even private methods are
> allowed to be overwritten, or added through subclasses and others.
>
> I look forward to hear some comments on these
>
> bye blackdrag
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-jsr] another try on groovy's features

Jochen Theodorou
Dierk Koenig schrieb:

> I'd say that although implementation-vise Groovy adds methods at runtime,
> there currently is no easy way for the application programmer to use
> that feature.
> In Ruby for example, I can do:
>  class_eval("\ndef bla_mehod\n"+my_method_body+"\nend")}
> which results in having bla_mehtod() added to my current class.
> Doing the  same in Groovy would be really tricky.
>
> So from an application programmers perspective, I think we can
> forget about the scenario above in Groovy and go for adding
> methods at compiletime.

with adding methods I didn't ment to add methods to the class, I ment
that methods are going to be visible as if they where part of the class.
In the end it's just about adding the method to the MetaClass. Of course
we could do a function class_eval... that would not be too difficult.
let us say Foo is a class, Foo.class.methods is a collection containing
the methods of that class, but only the methods that are in the
bytecode. As I can't exchange Foo with another class to add some methods
(I can of course make another Foo, with a different classloader, but
then it's still no exchanging) and as long as we don't overwrite the
getMethods method from class, this will be still so.

The use construct is an example of how methods are added to a class for
the runtime. The process of injecting methods throught
DefaultGroovyMethods is nearly the same, the use-construct is just a bit
more restricted to avoid problems (being able to remove the methods
after leaving the block, not interfering with other Threads).

bye blackdrag
Reply | Threaded
Open this post in threaded view
|

RE: [groovy-jsr] another try on groovy's features

Dierk König
Well, yes and no :-)

When I say 'adding dynamically at runtime' I mean something
like in the Ruby example where you have the
_code_of_the_method_ in let's say a String.

This you cannot do easily with MetaClass and 'use', since
you have to provide a _class_ that implements the
method that should be added.
(Ok, you could create this class dynamically, which is
why I called it 'tricky' rather than 'not possible')

cheers
Mittie

> -----Original Message-----
> From: Jochen Theodorou [mailto:[hidden email]]
> Sent: Samstag, 5. November 2005 14:21
> To: [hidden email]
> Subject: Re: [groovy-jsr] another try on groovy's features
>
>
> Dierk Koenig schrieb:
>
> > I'd say that although implementation-vise Groovy adds methods
> at runtime,
> > there currently is no easy way for the application programmer to use
> > that feature.
> > In Ruby for example, I can do:
> >  class_eval("\ndef bla_mehod\n"+my_method_body+"\nend")}
> > which results in having bla_mehtod() added to my current class.
> > Doing the  same in Groovy would be really tricky.
> >
> > So from an application programmers perspective, I think we can
> > forget about the scenario above in Groovy and go for adding
> > methods at compiletime.
>
> with adding methods I didn't ment to add methods to the class, I ment
> that methods are going to be visible as if they where part of the class.
> In the end it's just about adding the method to the MetaClass. Of course
> we could do a function class_eval... that would not be too difficult.
> let us say Foo is a class, Foo.class.methods is a collection containing
> the methods of that class, but only the methods that are in the
> bytecode. As I can't exchange Foo with another class to add some methods
> (I can of course make another Foo, with a different classloader, but
> then it's still no exchanging) and as long as we don't overwrite the
> getMethods method from class, this will be still so.
>
> The use construct is an example of how methods are added to a class for
> the runtime. The process of injecting methods throught
> DefaultGroovyMethods is nearly the same, the use-construct is just a bit
> more restricted to avoid problems (being able to remove the methods
> after leaving the block, not interfering with other Threads).
>
> bye blackdrag
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-jsr] another try on groovy's features

Jochen Theodorou
Dierk Koenig schrieb:

> Well, yes and no :-)
>
> When I say 'adding dynamically at runtime' I mean something
> like in the Ruby example where you have the
> _code_of_the_method_ in let's say a String.
>
> This you cannot do easily with MetaClass and 'use', since
> you have to provide a _class_ that implements the
> method that should be added.
> (Ok, you could create this class dynamically, which is
> why I called it 'tricky' rather than 'not possible')

each evaluate in groovy is creating a class.. that's normal for groovy
;) A normal evaluate is creating a class and executes it, why not only
create the class and add it's methods to MetaClass... That's not so
tricky I think.

bye blackdrag
Reply | Threaded
Open this post in threaded view
|

RE: [groovy-jsr] another try on groovy's features

Dierk König
> each evaluate in groovy is creating a class.. that's normal for groovy
> ;) A normal evaluate is creating a class and executes it, why not only
> create the class and add it's methods to MetaClass... That's not so
> tricky I think.

ok, only tricky for me, not tricky for you :-)
( and not tricky for Guillaume who played this
trick with the latest Scriptom changes...)

cheers
Mittie
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-jsr] another try on groovy's features

Guillaume Laforge
Administrator
On 05/11/05, Dierk Koenig <[hidden email]> wrote:
> ok, only tricky for me, not tricky for you :-)
> ( and not tricky for Guillaume who played this
> trick with the latest Scriptom changes...)

Hehe, true :-)

I'm not quite sure I'm following your ideas here, Jochen.
What do you mean exactly? We shouldn't be adding methods at compile
and/or runtime?
You want to restrict the way Groovy currently behaves?

I wish we could at least improve the "use" mechanism a little to allow
method closures instead of classes... And I'd even want to be able to
define new constructors, or new static methods through that same
mechanism. So I'd tend to ask for more rather than ask for less.

--
Guillaume Laforge
http://glaforge.free.fr/blog/groovy
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-jsr] another try on groovy's features

Jochen Theodorou
Guillaume Laforge schrieb:
[...]
> I'm not quite sure I'm following your ideas here, Jochen.
> What do you mean exactly? We shouldn't be adding methods at compile
> and/or runtime?
> You want to restrict the way Groovy currently behaves?

I wanted to hear comments about the points I listed. Some of them are in
groovy, others not. It's a question about what we want to have.

One of the biggest differences between Java and Groovy is, that I never
can be sure that a method is really called the way I thought it should
be called. It is always possible to overwrite the behavior of a class
without subclassing. In Java you have only subclassing to change the
behaviour of a class.

Where at first I had my problems with that style of thinking I like that
concept now very much. So I would not remove any of the features groovy
currently does have. That also means picking the method to execute is at
compiletime impossible. I can guess and prepare some bytecode for the
case and in ver many cases that will be ok, but in general it's
impossible. So any proposal going into the direction of calling a method
without asking MetaClass is against the groovy we currently have.

Example

class A {
   private foo(){}
   def bar(){foo()}
}

since there is only one method foo I could guess bar will execute this
method. But, as MetaClass is able to overwrite methods and exchange them
with another implementation I can't be sure about that. One more
difficult case would be:

class B extends A {
   def foo(){}
}

now B deifnes a foo(), which foo is bar calling now? When we say
subclassing is like overwriting, then the new foo method has to be
called... that's again very much against Java. Or maybe we say a private
method can't be overwritten, then what is in combined cases?

class A {
   private foo(o){}
   public  foo(String s){}
   def bar(o){foo(o)}
}

here I can't know which foo is ment if we use the runtime type of the
parameter of bar. and again this arises the question if B extends A:

class B extends A {
   def foo(o){}
   def foo(Integer i){}
}

what method will be called? Is it possible to overwrite foo(o) for B?

In Java I can change the behavior of classes only with overwriting
methods in subclasses. In groovy I can change it by overloading methods
and by overwriting. Of course we could say that a call from inside class
A should not see any private method of a subclass and we can say that a
call from a method defined in B should not access a private method of
any parent method.

I guess, since getMetaClass is static, that as long as getMetaClass is
used, calling foo(Object) from B, even when inside of method originally
defined in B, calls the new foo(Object) method instead of the old. this
means B is overwriting the private method from A. Additionally I am
unsure that the private method from A is visible.. so if B does not
overwrite foo(Object) it's like that method would not exist. Currently I
have no running groovy to test that, but a possibl program would be:

class A {
   private foo(){1}
   def invokeMethod(String name, Object args) {2}
   def bar(){foo()}
}

class B extends A {
   def foo(){3}
}

class C extends A {}

def a = new A()
assert a.bar() == 1
def b = new B()
assert b.bar() == 3
def c = new C()
assert c.bar() == 2

The simple question would be, is that ok? In Java it would be all the
same result.

> I wish we could at least improve the "use" mechanism a little to allow
> method closures instead of classes...

that shouldn't too complicated I think.

> And I'd even want to be able to define new constructors,

I haven't investigated about constructors

> or new static methods through that same mechanism.

but I think statics are not that important ;)

> So I'd tend to ask for more rather than ask for less.

sure ;)

bye blackdrag