CORE - Literal Instantiation breaks Object Model

Discussion in 'Ruby' started by Ilias Lazaridis, Jun 9, 2011.

  1. class String
    alias_method :eek:rig_initialize, :initialize
    def initialize(val)
    orig_initialize "OBSERVED: " + val
    end
    def my_method_test
    print self.inspect, " test\n"
    end
    end

    oo_string = String.new("The OO String")
    li_string = "The Literal String"

    print "Class: ", oo_string.class, " - content: ", oo_string, "\n"
    print "Class: ", li_string.class, " - content: ", li_string, "\n"
    oo_string.my_method_test
    li_string.my_method_test

    #OUTPUT
    #=> Class: String - content: OBSERVED: The OO String
    #=> Class: String - content: The Literal String
    #=> "OBSERVED: The OO String" test
    #=> "The Literal String" test

    -

    The behaviour of the class String has been altered, whilst using the
    standard mechanisms of the Object Model.

    To my huge surprise, although the li_string has been instantiated as
    an object of class String, the new initialize method was not called.

    This is essentially a defect, as the consistency of the Object Model
    breaks.

    The statement "Everything is an Object" becomes invalid, because e.g.
    a string object instantiated from a literal behaves differently that a
    string object instantiated normally via new() (although they share the
    same class, and thus should behave the same).

    My understanding is, that this is a know-issue and a trade-off due to
    performance issues.

    The questions are:

    b) Is there any way to track (intercept) the instantiation of objects
    (especially those instantiated from literals)
    1) without a C-level extension
    2) with a C-level extension

    The interception can be post instantiation.

    Underlying Requirement:

    Ability to track instantiation of every object within the system.

    ..

    --
    http://lazaridis.com
     
    Ilias Lazaridis, Jun 9, 2011
    #1
    1. Advertising

  2. On 09.06.2011 20:40, Ilias Lazaridis wrote:
    > class String
    > alias_method :eek:rig_initialize, :initialize
    > def initialize(val)
    > orig_initialize "OBSERVED: " + val
    > end
    > def my_method_test
    > print self.inspect, " test\n"
    > end
    > end
    >
    > oo_string = String.new("The OO String")
    > li_string = "The Literal String"
    >
    > print "Class: ", oo_string.class, " - content: ", oo_string, "\n"
    > print "Class: ", li_string.class, " - content: ", li_string, "\n"
    > oo_string.my_method_test
    > li_string.my_method_test
    >
    > #OUTPUT
    > #=> Class: String - content: OBSERVED: The OO String
    > #=> Class: String - content: The Literal String
    > #=> "OBSERVED: The OO String" test
    > #=> "The Literal String" test


    If that really had worked the way you’d expect it, you had ended up in an endless loop running out of stack levels soon. The reason for this is that
    each string literal would have to go through your special initialization routine, including your "The OO String" and, very subtle, the "OBSERVED: "
    string as well. The former would make oo_string into having two times the "OBSERVED: " prefix, once for initializing the string literal, and second
    inside of your explicit String.new() call. But the fact that "OBSERVED: " would require string initialization as well, would lead to an endless loop.

    To fix this infinite loop, one would have to initialize a string object prior to hooking initialize() like this:

    observed_prefix = "OBSERVED: "

    class String
    alias_method :eek:rig_initialize, :initialize
    def initialize(val)
    orig_initialize observed_prefix + val
    end
    […]
    end

    As Matz already pointed out, there are quite some good reasons for letting the parser translate literal constants into objects independent from the
    actual program flow.

    > The behaviour of the class String has been altered, whilst using the
    > standard mechanisms of the Object Model.
    >
    > To my huge surprise, although the li_string has been instantiated as
    > an object of class String, the new initialize method was not called.
    >
    > This is essentially a defect, as the consistency of the Object Model
    > breaks.


    Another question could be why »"OBSERVED: " + val« does not call initialize() on the resulting string right before that result is passed to
    orig_initialize. OTOH, this would lead to another endless loop.

    > My understanding is, that this is a know-issue and a trade-off due to
    > performance issues.


    As you see from the above, it’s not just a trade-off for performance reasons.

    > Underlying Requirement:
    > Ability to track instantiation of every object within the system.


    This is an interesting idea. I think you have to patch NEWOBJ() in the sources, at least.

    – Matthias
     
    Matthias Wächter, Jun 10, 2011
    #2
    1. Advertising

  3. On Thu, Jun 9, 2011 at 11:40 AM, Ilias Lazaridis <> wrote:

    > This is essentially a defect, as the consistency of the Object Model
    > breaks.
    >
    > The statement "Everything is an Object" becomes invalid, because
    > e.g. a string object instantiated from a literal behaves differently that a
    > string object instantiated normally via new() (although they share the
    > same class, and thus should behave the same).


    The logic in this argument is fundamentally flawed. "Everything is an
    Object" does not mean "every object of the same class behaves the
    same". Objects of the same class instantiated with different syntax
    regularly behave differently. Aside from literal vs. new, you have:

    #allocate vs. #new generally
    creation via other methods specific to a particular class (e.g., for
    Procs objects, proc {} vs. lambda {} vs. Proc.new vs ->() {} vs.
    method() vs. & to capture the block passed to a method)

    Others in the thread have explained adequately the practical reasons
    why you can't have <literal> be interpreted as
    <some-class>.new(<literal>) where both <literals> are identical [as
    that would produce infinite recursion], but aside from the
    practicality you are wrong on the basic theory: different
    initialization mechanism producing objects which are discernably
    different in the path of method calls involved in their instantiation
    and/or their behavior later in their lifecycle is not inconsistent
    with Ruby's object model, it is rather fundamental to it.
     
    Christopher Dicely, Jun 10, 2011
    #3
  4. On 10 ΙοÏν, 11:53, Matthias Wächter <> wrote:
    > On 09.06.2011 20:40, Ilias Lazaridis wrote:
    >
    > > class String
    > >    alias_method :eek:rig_initialize, :initialize
    > >    def initialize(val)
    > >      orig_initialize "OBSERVED: " + val


    #change to something like:

    orig_initialize val
    puts self.inspect

    > >    end
    > >    def my_method_test
    > >      print self.inspect, " test\n"
    > >    end
    > > end

    [...]

    > If that really had worked the way you’d expect it, you had ended up in an endless loop running out of stack levels soon. The reason for thisis that

    [...] - (elaborations of recursion problems with current showcase)

    I've understood your elaborations.

    You should not focus on the showcase code, which could be easily
    rewritten to not fall into this "trap" at all (e.g. placing a simple
    "puts object.inspect" in the constructor).

    Please see the reply to Mr. Matsumoto for more details on the essence
    of this issue (and the general essence subjecting development).

    > As you see from the above, it’s not just a trade-off for performance reasons.


    The performance problem is the central one. Everything else comes
    after, and should be solvable easily.

    > > Underlying Requirement:
    > > Ability to track instantiation of every object within the system.

    >
    > This is an interesting idea. I think you have to patch NEWOBJ() in the sources, at least.


    Is "NEWOBJ()" the central function, used system-wide (even from the
    parser)?

    ..

    --
    http://lazaridis.com
     
    Ilias Lazaridis, Jun 10, 2011
    #4
  5. On 9 Éïýí, 21:39, Ilias Lazaridis <> wrote:
    > class String
    >   alias_method :eek:rig_initialize, :initialize
    >   def initialize(val)
    >     orig_initialize "OBSERVED: " + val
    >   end
    >   def my_method_test
    >     print self.inspect, " test\n"
    >   end
    > end
    >
    > oo_string = String.new("The OO String")
    > li_string = "The Literal String"
    >
    > print "Class: ", oo_string.class, " - content: ", oo_string, "\n"
    > print "Class: ", li_string.class, " - content: ", li_string, "\n"
    > oo_string.my_method_test
    > li_string.my_method_test
    >
    > #OUTPUT
    > #=> Class: String - content: OBSERVED: The OO String
    > #=> Class: String - content: The Literal String
    > #=> "OBSERVED: The OO String" test
    > #=> "The Literal String" test
    >
    > -
    >
    > The behaviour of the class String has been altered, whilst using the
    > standard mechanisms of the Object Model.
    >
    > To my huge surprise, although the li_string has been instantiated as
    > an object of class String, the new initialize method was not called.
    >
    > This is essentially a defect, as the consistency of the Object Model
    > breaks.
    >
    > The statement "Everything is an Object" becomes invalid, because e.g.
    > a string object instantiated from a literal behaves differently that a
    > string object instantiated normally via new() (although they share the
    > same class, and thus should behave the same).
    >
    > My understanding is, that this is a know-issue and a trade-off due to
    > performance issues.
    >
    > The questions are:
    >
    > b) Is there any way to track (intercept) the instantiation of objects
    > (especially those instantiated from literals)
    >   1) without a C-level extension
    >   2) with a C-level extension
    >
    > The interception can be post instantiation.
    >
    > Underlying Requirement:
    >
    > Ability to track instantiation of every object within the system.


    Related Issue:

    Literal Instantiation breaks Object Model
    http://redmine.ruby-lang.org/issues/4893

    Related Issue (Attempt to workaround)

    Provide Class#cb_object_instantiated_from_literal(object)
    http://redmine.ruby-lang.org/issues/4845

    ..

    --
    http://lazaridis.com
     
    Ilias Lazaridis, Jun 21, 2011
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    587
    Salt_Peter
    Dec 25, 2006
  2. D Stanford
    Replies:
    8
    Views:
    863
    scottcarl
    May 10, 2007
  3. Ken Fine
    Replies:
    8
    Views:
    1,384
    Walter Wang [MSFT]
    Aug 29, 2007
  4. Anonieko Ramos

    What's wrong with rpc-literal? Why use doc-literal?

    Anonieko Ramos, Sep 27, 2004, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    392
    Anonieko Ramos
    Sep 27, 2004
  5. Ilias Lazaridis

    CORE - Object Instantiation and Location

    Ilias Lazaridis, May 26, 2011, in forum: Ruby
    Replies:
    16
    Views:
    320
    Ilias Lazaridis
    May 31, 2011
Loading...

Share This Page