Can we create a Ruby object lazily?

Hi,

class Foo
  def initialize(a , b)
     @a = a
     @b = b
  end
end

Foo.new(1, 3) # will work
Foo.new(1) # will create Argument error.

Can I create the Foo object lazily ?

I want the below not to raise error, rather wait until it gets all its mandatory arguments. Hoping it to work similar to Proc#curry.

Foo.new(1) # shouldn't raise error, rather do as I mentioned below.

···

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

class Foo
  def initialize(a , b=nil)
     @a = a
     @b = b
  end
end

Foo.new(1)

···

On Mon Feb 09 2015 at 12:49:10 PM Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Hi,

class Foo
  def initialize(a , b)
     @a = a
     @b = b
  end
end

Foo.new(1, 3) # will work
Foo.new(1) # will create Argument error.

Can I create the Foo object lazily ?

I want the below not to raise error, rather wait until it gets all its
mandatory arguments. Hoping it to work similar to Proc#curry.

Foo.new(1) # shouldn't raise error, rather do as I mentioned below.

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.

--Brian Kernighan

Nah! That's not what I asked. I want to delay the instance creation of Foo, until it gets all its required arguments. For me `a` and `b` both are required arguments.

Hints: Proc#curry. :slight_smile:

···

On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:

class Foo
  def initialize(a , b=nil)
     @a = a
     @b = b
  end
end

Foo.new(1)

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

How about this:

  module CurriedNew
    def new(*args)
      -> *a {
        allocate.tap { |obj|
          obj.__send__(:initialize, *a)
        }
      }.curry(instance_method(:initialize).arity).(*args)
    end
  end

  class Foo
    extend(CurriedNew)

    def initialize(a, b)
      puts "a: #{a}, b: #{b}"
    end
  end

Obviously this won't work when Foo#initialize's arity isn't fixed.

···

On Mon, 09 Feb 2015 23:16:38 +0630 Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Hi,

class Foo
  def initialize(a , b)
     @a = a
     @b = b
  end
end

Foo.new(1, 3) # will work
Foo.new(1) # will create Argument error.

Can I create the Foo object lazily ?

I want the below not to raise error, rather wait until it gets all its mandatory arguments. Hoping it to work similar to Proc#curry.

Foo.new(1) # shouldn't raise error, rather do as I mentioned below.

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

That's not really lazy so much as having a default value for b:

class Foo
  def initialize(a, b = 2)
    @a = a
    @b = b
  end
end

Now if you want to only worry about values when you access them, you
definitely nedd to have a default value either in the constructor, or in
the accessor function:

class Foo
  def b
    @b ||= 2
    @b
  end
end

This initializes @b at the point when it's accessed by an outside
entity, but only initializes it if it wasn't already defined.

···

On Mon, Feb 09, 2015 at 11:16:38PM +0630, Arup Rakshit wrote:

Hi,

class Foo
  def initialize(a , b)
     @a = a
     @b = b
  end
end

Foo.new(1, 3) # will work
Foo.new(1) # will create Argument error.

Can I create the Foo object lazily ?

I want the below not to raise error, rather wait until it gets all its mandatory arguments. Hoping it to work similar to Proc#curry.

Foo.new(1) # shouldn't raise error, rather do as I mentioned below.

--
Darryl L. Pierce <mcpierce@gmail.com>

Famous last words:
   "I wonder what happens if we do it this way?"

Well, I'd like to simple be snarky and say "don't call Foo.new until you have both prerequisite arguments", but instead, let me ask you two questions:

What would you expect Foo.new(1) to be?
What do you envision it would look like to later supply the 'b'? (and can that value actually be nil?)

-Rob

···

On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> wrote:

On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:

class Foo
def initialize(a , b=nil)
    @a = a
    @b = b
end
end

Foo.new(1)

Nah! That's not what I asked. I want to delay the instance creation of Foo, until it gets all its required arguments. For me `a` and `b` both are required arguments.

Hints: Proc#curry. :slight_smile:

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.

--Brian Kernighan

···

On Mon, Feb 9, 2015 at 1:41 PM, Rob Biedenharn <rob.biedenharn@gmail.com> wrote:

On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> wrote:

> On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:
>> class Foo
>> def initialize(a , b=nil)
>> @a = a
>> @b = b
>> end
>> end
>>
>> Foo.new(1)
>>
>
> Nah! That's not what I asked. I want to delay the instance creation of
Foo, until it gets all its required arguments. For me `a` and `b` both are
required arguments.
>
> Hints: Proc#curry. :slight_smile:
>
> --
> ================
> Regards,
> Arup Rakshit
> ================
> Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.
>
> --Brian Kernighan

Well, I'd like to simple be snarky and say "don't call Foo.new until you
have both prerequisite arguments", but instead, let me ask you two
questions:

What would you expect Foo.new(1) to be?
What do you envision it would look like to later supply the 'b'? (and can
that value actually be nil?)

-Rob

>> class Foo
>> def initialize(a , b=nil)
>> @a = a
>> @b = b
>> end
>> end
>>
>> Foo.new(1)
>>
>
> Nah! That's not what I asked. I want to delay the instance creation of Foo, until it gets all its required arguments. For me `a` and `b` both are required arguments.
>
> Hints: Proc#curry. :slight_smile:
>

Well, I'd like to simple be snarky and say "don't call Foo.new until you have both prerequisite arguments", but instead, let me ask you two questions:

What would you expect Foo.new(1) to be?

Well, Look the below example first using Method#curry.

def any_method(a,b)
  "called"
end

m = method(:any_method).curry
n = m.call(1) # => #<Proc:0x9872144 (lambda)>
n.call(2) # => "called"

So, with the example, we can delay the method body execution if we needed using the `#curry` method. This example leads me to think to do the same with `#new` too. But that didn't work.

class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

Foo.method(:new).curry.call(1, 2) # => #<Foo:0x9871b54>
Foo.method(:new).curry.call(1)
# `initialize': wrong number of arguments (1 for 2) (ArgumentError)

So, even if I am currying the #new, it didn't work as the in the case of `#any_method`. If it could be done, then I might able to delay the creation of the Foo instance.

What do you envision it would look like to later supply the 'b'? (and can that value actually be nil?)

It can be any value.

-Rob

Am I clear now with my intention ?

Note: Method#curry has been added to Ruby core 2.2.0 (Class: Method (Ruby 2.2.0))

···

On Monday, February 09, 2015 02:41:58 PM Rob Biedenharn wrote:

On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> wrote:
> On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

Hi Darryl,

I think Arup wanted to use the word "lazy" meaning that the _object_
(not one of its arguments) is not instantiated until all arguments are
passed.

In your example, although you don't pass all arguments, the object is
created when you issue Foo.new(1) for example.

Best regards,
Abinoam Jr.

···

On Fri, Feb 13, 2015 at 5:44 PM, Darryl L. Pierce <mcpierce@gmail.com> wrote:

On Mon, Feb 09, 2015 at 11:16:38PM +0630, Arup Rakshit wrote:

Hi,

class Foo
  def initialize(a , b)
     @a = a
     @b = b
  end
end

Foo.new(1, 3) # will work
Foo.new(1) # will create Argument error.

Can I create the Foo object lazily ?

I want the below not to raise error, rather wait until it gets all its mandatory arguments. Hoping it to work similar to Proc#curry.

Foo.new(1) # shouldn't raise error, rather do as I mentioned below.

That's not really lazy so much as having a default value for b:

class Foo
  def initialize(a, b = 2)
    @a = a
    @b = b
  end
end

Now if you want to only worry about values when you access them, you
definitely nedd to have a default value either in the constructor, or in
the accessor function:

class Foo
  def b
    @b ||= 2
    @b
  end
end

This initializes @b at the point when it's accessed by an outside
entity, but only initializes it if it wasn't already defined.

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.blogspot.com/
Famous last words:
   "I wonder what happens if we do it this way?"

Ahh! It seems I can delay the creation of Foo instance :

class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

foo = Foo.method(:new).curry(2).call(1)
foo.call(2) # => #<Foo:0x877df64>
foo.call(2).foo_val # => "object created"

Can the same behavior be designed below 2.2.0 ? Any chance ?

···

On Tuesday, February 10, 2015 09:04:44 AM Arup Rakshit wrote:

On Monday, February 09, 2015 02:41:58 PM Rob Biedenharn wrote:
>
> On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> wrote:
>
> > On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:
> >> class Foo
> >> def initialize(a , b=nil)
> >> @a = a
> >> @b = b
> >> end
> >> end
> >>
> >> Foo.new(1)
> >>
> >
> > Nah! That's not what I asked. I want to delay the instance creation of Foo, until it gets all its required arguments. For me `a` and `b` both are required arguments.
> >
> > Hints: Proc#curry. :slight_smile:
> >
>
> Well, I'd like to simple be snarky and say "don't call Foo.new until you have both prerequisite arguments", but instead, let me ask you two questions:
>
> What would you expect Foo.new(1) to be?

Well, Look the below example first using Method#curry.

def any_method(a,b)
  "called"
end

m = method(:any_method).curry
n = m.call(1) # => #<Proc:0x9872144 (lambda)>
n.call(2) # => "called"

So, with the example, we can delay the method body execution if we needed using the `#curry` method. This example leads me to think to do the same with `#new` too. But that didn't work.

class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

Foo.method(:new).curry.call(1, 2) # => #<Foo:0x9871b54>
Foo.method(:new).curry.call(1)
# `initialize': wrong number of arguments (1 for 2) (ArgumentError)

So, even if I am currying the #new, it didn't work as the in the case of `#any_method`. If it could be done, then I might able to delay the creation of the Foo instance.

> What do you envision it would look like to later supply the 'b'? (and can that value actually be nil?)

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

--Brian Kernighan

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

···

On Tue, Feb 10, 2015 at 12:19 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

On Tuesday, February 10, 2015 09:04:44 AM Arup Rakshit wrote:
> On Monday, February 09, 2015 02:41:58 PM Rob Biedenharn wrote:
> >
> > On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> > wrote:
> >
> > > On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:
> > >> class Foo
> > >> def initialize(a , b=nil)
> > >> @a = a
> > >> @b = b
> > >> end
> > >> end
> > >>
> > >> Foo.new(1)
> > >>
> > >
> > > Nah! That's not what I asked. I want to delay the instance creation
of Foo, until it gets all its required arguments. For me `a` and `b` both
are required arguments.
> > >
> > > Hints: Proc#curry. :slight_smile:
> > >
> >
> > Well, I'd like to simple be snarky and say "don't call Foo.new until
you have both prerequisite arguments", but instead, let me ask you two
questions:
> >
> > What would you expect Foo.new(1) to be?
>
> Well, Look the below example first using Method#curry.
>
> def any_method(a,b)
> "called"
> end
>
> m = method(:any_method).curry
> n = m.call(1) # => #<Proc:0x9872144 (lambda)>
> n.call(2) # => "called"
>
> So, with the example, we can delay the method body execution if we
needed using the `#curry` method. This example leads me to think to do the
same with `#new` too. But that didn't work.
>
> class Foo
> def initialize(a, b)
> end
>
> def foo_val
> "object created"
> end
> end
>
> Foo.method(:new).curry.call(1, 2) # => #<Foo:0x9871b54>
> Foo.method(:new).curry.call(1)
> # `initialize': wrong number of arguments (1 for 2) (ArgumentError)
>
> So, even if I am currying the #new, it didn't work as the in the case of
`#any_method`. If it could be done, then I might able to delay the creation
of the Foo instance.
>
> > What do you envision it would look like to later supply the 'b'? (and
can that value actually be nil?)
>

Ahh! It seems I can delay the creation of Foo instance :

class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

foo = Foo.method(:new).curry(2).call(1)
foo.call(2) # => #<Foo:0x877df64>
foo.call(2).foo_val # => "object created"

Can the same behavior be designed below 2.2.0 ? Any chance ?

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.

--Brian Kernighan

Dear Arup,

I was curious and did some experimentation.

Do you want something like this?

#!/usr/bin/env ruby

class MyClass
  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end

  def self.new_proc
    @new_proc ||= lambda { |a, b, c| self.new(a, b, c) }
  end

  def self.new_proc_curried
    @new_proc_curried ||= new_proc.curry
  end

  def self.lazy_new(*args)
    new_proc_curried.call(*args)
  end
end

p MyClass.lazy_new(1) # => a lambda
p MyClass.lazy_new(1, 2) # => a lambda
p MyClass.lazy_new(1, 2, 3) # => MyClass instance

Best regards,
Abinoam Jr.

···

On Tue, Feb 10, 2015 at 3:56 AM, Abinoam Jr. <abinoam@gmail.com> wrote:

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

On Tue, Feb 10, 2015 at 12:19 AM, Arup Rakshit <aruprakshit@rocketmail.com > > wrote:

On Tuesday, February 10, 2015 09:04:44 AM Arup Rakshit wrote:
> On Monday, February 09, 2015 02:41:58 PM Rob Biedenharn wrote:
> >
> > On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com> >> wrote:
> >
> > > On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:
> > >> class Foo
> > >> def initialize(a , b=nil)
> > >> @a = a
> > >> @b = b
> > >> end
> > >> end
> > >>
> > >> Foo.new(1)
> > >>
> > >
> > > Nah! That's not what I asked. I want to delay the instance creation
of Foo, until it gets all its required arguments. For me `a` and `b` both
are required arguments.
> > >
> > > Hints: Proc#curry. :slight_smile:
> > >
> >
> > Well, I'd like to simple be snarky and say "don't call Foo.new until
you have both prerequisite arguments", but instead, let me ask you two
questions:
> >
> > What would you expect Foo.new(1) to be?
>
> Well, Look the below example first using Method#curry.
>
> def any_method(a,b)
> "called"
> end
>
> m = method(:any_method).curry
> n = m.call(1) # => #<Proc:0x9872144 (lambda)>
> n.call(2) # => "called"
>
> So, with the example, we can delay the method body execution if we
needed using the `#curry` method. This example leads me to think to do the
same with `#new` too. But that didn't work.
>
> class Foo
> def initialize(a, b)
> end
>
> def foo_val
> "object created"
> end
> end
>
> Foo.method(:new).curry.call(1, 2) # => #<Foo:0x9871b54>
> Foo.method(:new).curry.call(1)
> # `initialize': wrong number of arguments (1 for 2) (ArgumentError)
>
> So, even if I am currying the #new, it didn't work as the in the case
of `#any_method`. If it could be done, then I might able to delay the
creation of the Foo instance.
>
> > What do you envision it would look like to later supply the 'b'? (and
can that value actually be nil?)
>

Ahh! It seems I can delay the creation of Foo instance :

class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

foo = Foo.method(:new).curry(2).call(1)
foo.call(2) # => #<Foo:0x877df64>
foo.call(2).foo_val # => "object created"

Can the same behavior be designed below 2.2.0 ? Any chance ?

--

Regards,
Arup Rakshit

Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.

--Brian Kernighan

Hey,

Usually in this type of Object Construction, it is better to use something like a ‘Builder Pattern’ which makes construction of an object as mentioned by you.

Check Builder Pattern here 'http://en.wikipedia.org/wiki/Builder_pattern&#39;

Thanks and Regards

Rajeev N B
Application Developer

···

On Tuesday, 10 February 2015 at 12:26 pm, Abinoam Jr. wrote:

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

On Tue, Feb 10, 2015 at 12:19 AM, Arup Rakshit <aruprakshit@rocketmail.com (mailto:aruprakshit@rocketmail.com)> wrote:
> On Tuesday, February 10, 2015 09:04:44 AM Arup Rakshit wrote:
> > On Monday, February 09, 2015 02:41:58 PM Rob Biedenharn wrote:
> > >
> > > On 2015-Feb-9, at 13:13 , Arup Rakshit <aruprakshit@rocketmail.com (mailto:aruprakshit@rocketmail.com)> wrote:
> > >
> > > > On Monday, February 09, 2015 05:51:02 PM George Drummond wrote:
> > > >> class Foo
> > > >> def initialize(a , b=nil)
> > > >> @a = a
> > > >> @b = b
> > > >> end
> > > >> end
> > > >>
> > > >> Foo.new(1)
> > > >>
> > > >
> > > > Nah! That's not what I asked. I want to delay the instance creation of Foo, until it gets all its required arguments. For me `a` and `b` both are required arguments.
> > > >
> > > > Hints: Proc#curry. :slight_smile:
> > > >
> > >
> > > Well, I'd like to simple be snarky and say "don't call Foo.new until you have both prerequisite arguments", but instead, let me ask you two questions:
> > >
> > > What would you expect Foo.new(1) to be?
> >
> > Well, Look the below example first using Method#curry.
> >
> > def any_method(a,b)
> > "called"
> > end
> >
> > m = method(:any_method).curry
> > n = m.call(1) # => #<Proc:0x9872144 (lambda)>
> > n.call(2) # => "called"
> >
> > So, with the example, we can delay the method body execution if we needed using the `#curry` method. This example leads me to think to do the same with `#new` too. But that didn't work.
> >
> > class Foo
> > def initialize(a, b)
> > end
> >
> > def foo_val
> > "object created"
> > end
> > end
> >
> > Foo.method(:new).curry.call(1, 2) # => #<Foo:0x9871b54>
> > Foo.method(:new).curry.call(1)
> > # `initialize': wrong number of arguments (1 for 2) (ArgumentError)
> >
> > So, even if I am currying the #new, it didn't work as the in the case of `#any_method`. If it could be done, then I might able to delay the creation of the Foo instance.
> >
> > > What do you envision it would look like to later supply the 'b'? (and can that value actually be nil?)
> >
>
> Ahh! It seems I can delay the creation of Foo instance :
>
> class Foo
> def initialize(a, b)
> end
>
> def foo_val
> "object created"
> end
> end
>
> foo = Foo.method(:new).curry(2).call(1)
> foo.call(2) # => #<Foo:0x877df64>
> foo.call(2).foo_val # => "object created"
>
> Can the same behavior be designed below 2.2.0 ? Any chance ?
>
> --
> ================
> Regards,
> Arup Rakshit
> ================
> Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
>
> --Brian Kernighan

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.
Best regards,Abinoam Jr.
Humm. Mine will work only in 2.2.0 as I mentioned . But for below version of 2.2.0, you need to use :-
class Foo def initialize(a, b) end
def foo_val "object created" endend
foo = Foo.method(:new).to_proc.curry(2).call(1) # I USED to_procp foo.call(2) # => #<Foo:0x877df64>p foo.call(2).foo_val # => "object created"

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

<Resending as the Rich text killed the previous email. :-(>
Humm. Mine will work only in 2.2.0 as I mentioned . But for below version of 2.2.0, you need to use :-

========================class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

foo = Foo.method(:new).to_proc.curry(2).call(1) # I USED to_proc
p foo.call(2) # => #<Foo:0x877df64>

p foo.call(2).foo_val # => "object created"

Hi Arup,

I didn't remembered "to_proc" laying aroud. I liked it.

A "modified" version follows.

class MyClass
  module ClassMethods
    def new_proc
      method(:new).to_proc
    end

    def new_proc_curried
      new_proc.curry(initialize_arity)
    end

    def lazy_new(*args)
      new_proc_curried.call(*args)
    end

    private

    def initialize_arity
      instance_method(:initialize).arity
    end
  end

  extend ClassMethods

  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end
end

p MyClass.lazy_new(1) # => a lambda
p MyClass.lazy_new(1, 2) # => a lambda
p MyClass.lazy_new(1, 2, 3) # => MyClass instance

···

On Tue, Feb 10, 2015 at 4:36 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

<Resending as the Rich text killed the previous email. :-(>
Humm. Mine will work only in 2.2.0 as I mentioned . But for below version
of 2.2.0, you need to use :-

========================class Foo
  def initialize(a, b)
  end

  def foo_val
    "object created"
  end
end

foo = Foo.method(:new).to_proc.curry(2).call(1) # I USED to_proc
p foo.call(2) # => #<Foo:0x877df64>

p foo.call(2).foo_val # => "object created"

Abinoam,

This is super duper! You won the crown. :slight_smile: This is a Ruby-Procise way to implement the builder pattern ;). I liked it.

Regards,
Arup Rakshit

Hi Arup,

I didn't remembered "to_proc" laying aroud. I liked it.

A "modified" version follows.

class MyClass
  module ClassMethods
    def new_proc
      method(:new).to_proc
    end

    def new_proc_curried
      new_proc.curry(initialize_arity)
    end

    def lazy_new(*args)
      new_proc_curried.call(*args)
    end

    private

    def initialize_arity
      instance_method(:initialize).arity
    end
  end

  extend ClassMethods

  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end
end

p MyClass.lazy_new(1) # => a lambda
p MyClass.lazy_new(1, 2) # => a lambda
p MyClass.lazy_new(1, 2, 3) # => MyClass instance

Hi Arup,

···

On Tuesday, 10 February 2015 6:30 PM, Abinoam Jr. <abinoam@gmail.com> wrote:
On Tue, Feb 10, 2015 at 4:36 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

<Resending as the Rich text killed the previous email. :-(>
Humm. Mine will work only in 2.2.0 as I mentioned . But for below version of 2.2.0, you need to use :-

========================class Foo

def initialize(a, b)
end

def foo_val
   "object created"
end
end

foo = Foo.method(:new).to_proc.curry(2).call(1) # I USED to_proc
p foo.call(2) # => #<Foo:0x877df64>

p foo.call(2).foo_val # => "object created"

If you need to collect constructor arguments before creating the instance
you could also do this:

class Array
  def new(clazz, &b)
    clazz.new(*self, &b)
  end
end

class MyClass
  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end
end

c = [1]
c << 2
c << 3

p c

p c.new(MyClass)

I am still not convinced that this is needed or a good idea. What would be
the use cases for lazy creation?

Kind regards

robert

···

On Tue, Feb 10, 2015 at 2:00 PM, Abinoam Jr. <abinoam@gmail.com> wrote:

Hi Arup,

I didn't remembered "to_proc" laying aroud. I liked it.

A "modified" version follows.

class MyClass
  module ClassMethods
    def new_proc
      method(:new).to_proc
    end

    def new_proc_curried
      new_proc.curry(initialize_arity)
    end

    def lazy_new(*args)
      new_proc_curried.call(*args)
    end

    private

    def initialize_arity
      instance_method(:initialize).arity
    end
  end

  extend ClassMethods

  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end
end

p MyClass.lazy_new(1) # => a lambda
p MyClass.lazy_new(1, 2) # => a lambda
p MyClass.lazy_new(1, 2, 3) # => MyClass instance

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/

If you're willing to accept a method other than Class.new, I prefer
this approach to currying, because it's easier to inspect the state of
the build-in-progress:

class Builder
  def initialize(klass)
    @klass = klass
    @arity = klass.instance_method(:initialize).arity
    @args =
  end

  def build(*args)
    @args.concat(args)
    if @args.length == @arity
      @klass.method(:new).call(*@args)
    elsif @args.length > @arity
      raise "Too many arguments to #@klass.new: expected #@arity, got #@args"
    else
      self
    end
  end
end

module Buildable
  def lazy_init(*args)
    Builder.new(self).build(*args)
  end
end

class Foo
  extend Buildable

  def initialize(a, b, c)
    puts "Initialized with #{[a,b,c]}"
  end
end

a = Foo.lazy_init(1,2)
p a
a = a.build(3)
p a

martin

···

On Tue, Feb 10, 2015 at 5:11 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Abinoam,

This is super duper! You won the crown. :slight_smile: This is a Ruby-Procise way to implement the builder pattern ;). I liked it.

Regards,
Arup Rakshit

On Tuesday, 10 February 2015 6:30 PM, Abinoam Jr. <abinoam@gmail.com> wrote:

Hi Arup,

I didn't remembered "to_proc" laying aroud. I liked it.

A "modified" version follows.

class MyClass
  module ClassMethods
    def new_proc
      method(:new).to_proc
    end

    def new_proc_curried
      new_proc.curry(initialize_arity)
    end

    def lazy_new(*args)
      new_proc_curried.call(*args)
    end

    private

    def initialize_arity
      instance_method(:initialize).arity
    end
  end

  extend ClassMethods

  attr_reader :sum

  def initialize(a, b, c)
    @sum = a + b + c
  end
end

p MyClass.lazy_new(1) # => a lambda
p MyClass.lazy_new(1, 2) # => a lambda
p MyClass.lazy_new(1, 2, 3) # => MyClass instance

On Tue, Feb 10, 2015 at 4:36 AM, Arup Rakshit <aruprakshit@rocketmail.com> wrote:

Hi Arup,

I've tested your snippet on 2.1.0 and it doesn't work.

Best regards,
Abinoam Jr.

<Resending as the Rich text killed the previous email. :-(>
Humm. Mine will work only in 2.2.0 as I mentioned . But for below version of 2.2.0, you need to use :-

========================class Foo

def initialize(a, b)
end

def foo_val
   "object created"
end
end

foo = Foo.method(:new).to_proc.curry(2).call(1) # I USED to_proc
p foo.call(2) # => #<Foo:0x877df64>

p foo.call(2).foo_val # => "object created"