Initialize always

It is rather a common occurrence that I find myself creating a mixin module
that has instance vars in it, for example:

  module Example
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
  end

Now the class that includes this module requires @examples to be predefined.
But short of adding @examples = [] to the #initialize method of the class
(which would ruin the goal of using the module to begin with) one ends up
doing something like:

  module Example
    def add( ex )
      ( @examples || [] ) << ex
    end
  end

But this seems quite computationally wasteful to me. Another alternative is to
add an intialize to the module and a super call to the class:

  module Example
    def initialize
      @examples = []
    end
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
    def initialize
      super()
    end
  end

But again, by having to modify the class we're defeating the one of the basic
purposes of module "componentization": SOC.

So I was thinking/wondering if it were possible to have an a variant
initializer that _always_ calls super? it would make sense to have one for
both begin and end positions. So the above example becomes:

  module Example
    def initialize_pre
      @examples = []
    end
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
  end

When X.new is called initialize_pre automatically proceeds the #initialize
method. #initialize_post would do the same for when the #initialize method
finishes. Of course these would automatically work their way up the entire
class/module chain.

BTW this is not necessarily the same as method wraps (consider the subtle
differences) --rather these are strictly callbacks of initialization.

Thoughts?
T.

Make that:

 \( @examples ||= \[\] \) &lt;&lt; ex

T.

···

On Saturday 27 November 2004 12:26 pm, trans. (T. Onoma) wrote:

module Example
def add( ex )
( @examples || ) << ex
end
end

trans. (T. Onoma) wrote:

So I was thinking/wondering if it were possible to have an a variant initializer that _always_ calls super? it would make sense to have one for both begin and end positions. So the above example becomes:

  module Example
    def initialize_pre
      @examples =
    end
    def add( ex )
      @examples << ex
    end
  end

Rite will have AOP-style method:pre, :post and :wrap hooks. However I'd also like to see a solution for this quite common problem before the release of Ruby 2. Maybe there already is a good way of doing this that I'm just not aware of.

One way to get this behavior now would be to implement
Module#included, using it with Kernel.set_trace_func to watch
instantiation for the including class, and having it call your
initialize_pre and initialize_post methods.

But since it's possible to have only one tracer at a time, that seems
like a pretty inflexible solution.

Sam

···

On Sun, 28 Nov 2004 02:26:53 +0900, trans. (T. Onoma) <transami@runbox.com> wrote:

So I was thinking/wondering if it were possible to have an a variant
initializer that _always_ calls super? it would make sense to have one for
both begin and end positions. So the above example becomes:

  module Example
    def initialize_pre
      @examples =
    end
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
  end

When X.new is called initialize_pre automatically proceeds the #initialize
method. #initialize_post would do the same for when the #initialize method
finishes. Of course these would automatically work their way up the entire
class/module chain.

BTW this is not necessarily the same as method wraps (consider the subtle
differences) --rather these are strictly callbacks of initialization.

Thoughts?
T.

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200411271226.46187.transami@runbox.com...

It is rather a common occurrence that I find myself creating a mixin

module

that has instance vars in it, for example:

  module Example
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
  end

Now the class that includes this module requires @examples to be

predefined.

But short of adding @examples = to the #initialize method of the

class

(which would ruin the goal of using the module to begin with) one ends

up

doing something like:

  module Example
    def add( ex )
      ( @examples || ) << ex
    end
  end

But this seems quite computationally wasteful to me. Another alternative

is to

add an intialize to the module and a super call to the class:

  module Example
    def initialize
      @examples =
    end
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
    def initialize
      super()
    end
  end

But again, by having to modify the class we're defeating the one of the

basic

purposes of module "componentization": SOC.

So I was thinking/wondering if it were possible to have an a variant
initializer that _always_ calls super? it would make sense to have one

for

both begin and end positions. So the above example becomes:

  module Example
    def initialize_pre
      @examples =
    end
    def add( ex )
      @examples << ex
    end
  end

  class X
    include Examples
  end

When X.new is called initialize_pre automatically proceeds the

#initialize

method. #initialize_post would do the same for when the #initialize

method

finishes. Of course these would automatically work their way up the

entire

class/module chain.

BTW this is not necessarily the same as method wraps (consider the

subtle

differences) --rather these are strictly callbacks of initialization.

Thoughts?
T.

I think I did an RCR on this matter but I can't find it. Maybe I was stuck
or it got lost somewhere. I'll have to dig into this at home. If I find
the info I'll get back. From what I remember basically the idea was to
automatically invoke super under certain circumstances. The idea was to
do that depending on the argument list and the presence of an explicite
"super".

Kind regards

    robert

I doubt that's a good thing. To me pre, post and wrap are pretty much hacks.
And I do not believe these hooks will even work here. Consider:

  module M
    def initialize:pre
      print "A"
    end
    def initialize
      print "M"
    end
  end

  class C
    include M
    def initialize
      super
      print "C"
    end
  end

  C.new ; puts

what will be the output?

T.

···

On Saturday 27 November 2004 01:37 pm, Florian Gross wrote:

trans. (T. Onoma) wrote:
> So I was thinking/wondering if it were possible to have an a variant
> initializer that _always_ calls super? it would make sense to have one
> for both begin and end positions. So the above example becomes:
>
> module Example
> def initialize_pre
> @examples =
> end
> def add( ex )
> @examples << ex
> end
> end

Rite will have AOP-style method:pre, :post and :wrap hooks. However I'd
also like to see a solution for this quite common problem before the
release of Ruby 2. Maybe there already is a good way of doing this that
I'm just not aware of.

Cool. Let me know.

T.

···

On Monday 29 November 2004 04:22 am, Robert Klemme wrote:

I think I did an RCR on this matter but I can't find it. Maybe I was stuck
or it got lost somewhere. I'll have to dig into this at home. If I find
the info I'll get back. From what I remember basically the idea was to
automatically invoke super under certain circumstances. The idea was to
do that depending on the argument list and the presence of an explicite
"super".

"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag
news:310832F34jr8cU1@uni-berlin.de...

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200411271226.46187.transami@runbox.com...
> It is rather a common occurrence that I find myself creating a mixin
module
> that has instance vars in it, for example:
>
> module Example
> def add( ex )
> @examples << ex
> end
> end
>
> class X
> include Examples
> end
>
> Now the class that includes this module requires @examples to be
predefined.
> But short of adding @examples = to the #initialize method of the
class
> (which would ruin the goal of using the module to begin with) one ends
up
> doing something like:
>
> module Example
> def add( ex )
> ( @examples || ) << ex
> end
> end
>
> But this seems quite computationally wasteful to me. Another

alternative

is to
> add an intialize to the module and a super call to the class:
>
> module Example
> def initialize
> @examples =
> end
> def add( ex )
> @examples << ex
> end
> end
>
> class X
> include Examples
> def initialize
> super()
> end
> end
>
> But again, by having to modify the class we're defeating the one of

the

basic
> purposes of module "componentization": SOC.
>
> So I was thinking/wondering if it were possible to have an a variant
> initializer that _always_ calls super? it would make sense to have one
for
> both begin and end positions. So the above example becomes:
>
> module Example
> def initialize_pre
> @examples =
> end
> def add( ex )
> @examples << ex
> end
> end
>
> class X
> include Examples
> end
>
> When X.new is called initialize_pre automatically proceeds the
#initialize
> method. #initialize_post would do the same for when the #initialize
method
> finishes. Of course these would automatically work their way up the
entire
> class/module chain.
>
> BTW this is not necessarily the same as method wraps (consider the
subtle
> differences) --rather these are strictly callbacks of initialization.
>
> Thoughts?
> T.

I think I did an RCR on this matter but I can't find it. Maybe I was

stuck

or it got lost somewhere. I'll have to dig into this at home. If I find
the info I'll get back. From what I remember basically the idea was to
automatically invoke super under certain circumstances. The idea was to
do that depending on the argument list and the presence of an explicite
"super".

Finally today I found a sheet of paper while cleaning my desk. (It's good
to do that once in a while. :-))

It hadn't made it to an RCR though. The suggestion would have been this:
if a Module defines method initialize without an argument list then
implicitely change that to be initialise(*a,&b) and implicitely add super
as first line in the method: Thus

module Foo
  def initialize
    @bar = 0
  end
end

becomes

module Foo
  def initialize(*a,&b)
    super
    @bar = 0
  end
end

Note: identifiers for arguments and block may have to be generated to be
unique.

All other cases (i.e. combinations of with / without argument list and
with / without occurrence of "super" in the body of this method) should
remain unchanged, because they would cause too much hassle.

Pro: this change allows for easy initialization of instance variables
needed by modules even if there are multiple modules included:

class Base
  def initialize(x)
    @x = x
   end
end

class Test < Base
  include Foo
  include Bar

  def initialize(a, b)
     super(a)
     @b = b
  end
end

What do others think?

Kind regards

    robert

Not sure I explained this well enough. Let me elaborate just a tad.

Consider:

  module M
    def initialize:pre
      print "A"
    end
    def initialize
      print "M"
    end
  end

  class C
    include M
    def initialize
      super
      print "C"
    end
  end

  C.new ; puts

what will be the output?

Of course the answer is
  
  #-> AMC

But why? Now consider the slight change:

   class C
     include M
     def initialize
       print "C"
       super
     end
   end

Is the result CAM or ACM ?

HTH,
T.

···

On Saturday 27 November 2004 03:06 pm, trans. (T. Onoma) wrote:

Hi --

Finally today I found a sheet of paper while cleaning my desk. (It's good
to do that once in a while. :-))

It hadn't made it to an RCR though. The suggestion would have been this:
if a Module defines method initialize without an argument list then
implicitely change that to be initialise(*a,&b) and implicitely add super
as first line in the method: Thus

module Foo
def initialize
   @bar = 0
end
end

becomes

module Foo
def initialize(*a,&b)
   super
   @bar = 0
end
end

Note: identifiers for arguments and block may have to be generated to be
unique.

All other cases (i.e. combinations of with / without argument list and
with / without occurrence of "super" in the body of this method) should
remain unchanged, because they would cause too much hassle.

Pro: this change allows for easy initialization of instance variables
needed by modules even if there are multiple modules included:

class Base
def initialize(x)
   @x = x
  end
end

class Test < Base
include Foo
include Bar

def initialize(a, b)
    super(a)
    @b = b
end
end

What do others think?

My initial reaction is that it's too magic for my taste... too much
written in "invisible ink". If I write: def meth; ...; end then I
want it to fail if it's called with arguments. But I'm also not
understanding the 'pro' point very thoroughly, or maybe I've just
never had this problem. I think I'm just being thick, but can you
explain a little more how/when/why this would be useful?

David

···

On Wed, 15 Dec 2004, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

Robert Klemme wrote:

module Foo
  def initialize
    @bar = 0
  end
end

becomes

module Foo
  def initialize(*a,&b)
    super
    @bar = 0
  end
end

Pro: this change allows for easy initialization of instance variables
needed by modules even if there are multiple modules included:

What do others think?

What happens when somebody naively updates the first version of module Foo from above as follows?

module Foo
   def initialize(default = 0)
     @bar = default
   end
end

It might seem like a safe enough change, but it wouldn't be.

I think you can't change the meaning of "initialize" that drastically, but you could define a new "super_initialize" if it was really important.

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

trans. (T. Onoma) wrote:

Not sure I explained this well enough. Let me elaborate just a tad.

> Consider:
>
> module M
> def initialize:pre
> print "A"
> end
> def initialize
> print "M"
> end
> end
>
> class C
> include M
> def initialize
> super
> print "C"
> end
> end
>
> C.new ; puts
>
> what will be the output?

Of course the answer is
    #-> AMC

I'm not sure it is that. I'm waiting for somebody that knows how this will be handled in Rite to answer. I can see AMC being a valid answer of course, but I am not sure if it will be the one Rite gives.

···

On Saturday 27 November 2004 03:06 pm, trans. (T. Onoma) wrote:

"Glenn Parker" <glenn.parker@comcast.net> schrieb im Newsbeitrag
news:41C03A4D.90503@comcast.net...

Robert Klemme wrote:
>
> module Foo
> def initialize
> @bar = 0
> end
> end
>
> becomes
>
> module Foo
> def initialize(*a,&b)
> super
> @bar = 0
> end
> end
>
> Pro: this change allows for easy initialization of instance variables
> needed by modules even if there are multiple modules included:
>
> What do others think?

What happens when somebody naively updates the first version of module
Foo from above as follows?

module Foo
   def initialize(default = 0)
     @bar = default
   end
end

It might seem like a safe enough change, but it wouldn't be.

Good point.

I think you can't change the meaning of "initialize" that drastically,
but you could define a new "super_initialize" if it was really

important.

What would that do? The aim was to have a method that does initialization
but does not disturb the calling chain of initialize. Maybe it would be
better to have a new method (initialize_locally or whatever) that does not
call super and is called individually, i.e. for each class in the chain of
ancestors.

Kind regards

    robert

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0412150450290.690@wobblini...

Hi --

> Finally today I found a sheet of paper while cleaning my desk. (It's

good

> to do that once in a while. :-))
>
> It hadn't made it to an RCR though. The suggestion would have been

this:

> if a Module defines method initialize without an argument list then
> implicitely change that to be initialise(*a,&b) and implicitely add

super

> as first line in the method: Thus
>
> module Foo
> def initialize
> @bar = 0
> end
> end
>
> becomes
>
> module Foo
> def initialize(*a,&b)
> super
> @bar = 0
> end
> end
>
> Note: identifiers for arguments and block may have to be generated to

be

> unique.
>
> All other cases (i.e. combinations of with / without argument list and
> with / without occurrence of "super" in the body of this method)

should

> remain unchanged, because they would cause too much hassle.
>
> Pro: this change allows for easy initialization of instance variables
> needed by modules even if there are multiple modules included:
>
> class Base
> def initialize(x)
> @x = x
> end
> end
>
> class Test < Base
> include Foo
> include Bar
>
> def initialize(a, b)
> super(a)
> @b = b
> end
> end
>
> What do others think?

My initial reaction is that it's too magic for my taste... too much
written in "invisible ink". If I write: def meth; ...; end then I
want it to fail if it's called with arguments. But I'm also not
understanding the 'pro' point very thoroughly, or maybe I've just
never had this problem. I think I'm just being thick, but can you
explain a little more how/when/why this would be useful?

Well, often you write a class and mixin a module that needs some state.
Currently the only safe way to initialize that is to write it like this:

module Foo
  def initialize(*a,&b)
    super
    @foo_state = "something"
  end
end

If you do not define initialize for a module you end up writing accessors
like this all the time:

module Foo
  def foo_state
    @foo_state ||= "something"
  end
end

Which is less performant and has slightly different semantics (just think
of the case that nil or false is a legal value for @foo_state).

So the idea was to safe some typing and change initialize methods without
arguments and without a super in them the way I described.

Another option would be to disallow arguments and super for module
initialize and to do the change (implicit super etc.), which has some
reasons in favour of it but may break a lot of existing code. If I was
designing module initialization that's probably the way I'd do it.
Alternatively we could have a special method local_initialize that is
called automatically for each class in #ancestors.

Kind regards

    robert

···

On Wed, 15 Dec 2004, Robert Klemme wrote:

Yes, I think your idea is a good one for what it accomplishes but not for how
it does so. It agree with David, it is too "magic". Nonetheless, your
analysis is right on, and I think something really ought to be done about
this. IMO, It happens far too often to continue to be overlooked.

I also like the implicit super notion. But I think the best way to achieve it
may be via an initialize callback. Barring that that your idea of an always
called local_initialize is, AFAICT, the remaining alternative --and perhaps
the better one anyways.

T.

···

On Wednesday 15 December 2004 09:47 am, Robert Klemme wrote:

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0412150450290.690@wobblini...

> Hi --
>
> On Wed, 15 Dec 2004, Robert Klemme wrote:
> > Finally today I found a sheet of paper while cleaning my desk. (It's

good

> > to do that once in a while. :-))
> >
> > It hadn't made it to an RCR though. The suggestion would have been

this:
> > if a Module defines method initialize without an argument list then
> > implicitely change that to be initialise(*a,&b) and implicitely add

super

> > as first line in the method: Thus
> >
> > module Foo
> > def initialize
> > @bar = 0
> > end
> > end
> >
> > becomes
> >
> > module Foo
> > def initialize(*a,&b)
> > super
> > @bar = 0
> > end
> > end
> >
> > Note: identifiers for arguments and block may have to be generated to

be

> > unique.
> >
> > All other cases (i.e. combinations of with / without argument list and
> > with / without occurrence of "super" in the body of this method)

should

> > remain unchanged, because they would cause too much hassle.
> >
> > Pro: this change allows for easy initialization of instance variables
> > needed by modules even if there are multiple modules included:
> >
> > class Base
> > def initialize(x)
> > @x = x
> > end
> > end
> >
> > class Test < Base
> > include Foo
> > include Bar
> >
> > def initialize(a, b)
> > super(a)
> > @b = b
> > end
> > end
> >
> > What do others think?
>
> My initial reaction is that it's too magic for my taste... too much
> written in "invisible ink". If I write: def meth; ...; end then I
> want it to fail if it's called with arguments. But I'm also not
> understanding the 'pro' point very thoroughly, or maybe I've just
> never had this problem. I think I'm just being thick, but can you
> explain a little more how/when/why this would be useful?

Well, often you write a class and mixin a module that needs some state.
Currently the only safe way to initialize that is to write it like this:

module Foo
  def initialize(*a,&b)
    super
    @foo_state = "something"
  end
end

If you do not define initialize for a module you end up writing accessors
like this all the time:

module Foo
  def foo_state
    @foo_state ||= "something"
  end
end

Which is less performant and has slightly different semantics (just think
of the case that nil or false is a legal value for @foo_state).

So the idea was to safe some typing and change initialize methods without
arguments and without a super in them the way I described.

Another option would be to disallow arguments and super for module
initialize and to do the change (implicit super etc.), which has some
reasons in favour of it but may break a lot of existing code. If I was
designing module initialization that's probably the way I'd do it.
Alternatively we could have a special method local_initialize that is
called automatically for each class in #ancestors.

Yes, I think your idea is a good one for what it accomplishes but not for how
it does so. It agree with David, it is too "magic". Nonetheless, your
analysis is right on, and I think something really ought to be done about
this. IMO, It happens far too often to continue to be overlooked.

I also like the implicit super notion. But I think the best way to achieve it
may be via an initialize callback. Barring that that your idea of an always
called local_initialize is, AFAICT, the remaining alternative --and perhaps
the better one anyways.

T.

···

On Wednesday 15 December 2004 09:47 am, Robert Klemme wrote:

[snip]

> > What do others think?
>
> My initial reaction is that it's too magic for my taste... too much
> written in "invisible ink". If I write: def meth; ...; end then I
> want it to fail if it's called with arguments. But I'm also not
> understanding the 'pro' point very thoroughly, or maybe I've just
> never had this problem. I think I'm just being thick, but can you
> explain a little more how/when/why this would be useful?

Well, often you write a class and mixin a module that needs some state.
Currently the only safe way to initialize that is to write it like this:

module Foo
  def initialize(*a,&b)
    super
    @foo_state = "something"
  end
end

If you do not define initialize for a module you end up writing accessors
like this all the time:

module Foo
  def foo_state
    @foo_state ||= "something"
  end
end

Which is less performant and has slightly different semantics (just think
of the case that nil or false is a legal value for @foo_state).

So the idea was to safe some typing and change initialize methods without
arguments and without a super in them the way I described.

Another option would be to disallow arguments and super for module
initialize and to do the change (implicit super etc.), which has some
reasons in favour of it but may break a lot of existing code. If I was
designing module initialization that's probably the way I'd do it.
Alternatively we could have a special method local_initialize that is
called automatically for each class in #ancestors.