Forum: Ruby java guilt

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Giles B. (Guest)
on 2007-03-14 22:25
(Received via mailing list)
I just solved a problem by adding an instance method to String.

It makes for very elegant code elsewhere within the application.

Yet I can't shake the feeling I've done something dirty.

I think there needs to be a group like "Recovering Java Programmers
Anonymous" or somehting.
David A. Black (Guest)
on 2007-03-14 22:39
(Received via mailing list)
Hi --

On 3/14/07, Giles B. <removed_email_address@domain.invalid> wrote:
> I just solved a problem by adding an instance method to String.
>
> It makes for very elegant code elsewhere within the application.
>
> Yet I can't shake the feeling I've done something dirty.
>
> I think there needs to be a group like "Recovering Java Programmers
> Anonymous" or somehting.

Feeling squeamish about changing the core language isn't the sole
prerogative of recovering Java programmers :-)  There's still no good
answer to the question of how to do it safely and in a way that does
not risk conflicts, though there are various "better practices".  My
favorite is "extend", which lets you confine changes to particular
objects.  That's not always very efficient, though.


David
Giles B. (Guest)
on 2007-03-14 22:56
(Received via mailing list)
On 3/14/07, David A. Black <removed_email_address@domain.invalid> wrote:
> > Anonymous" or somehting.
>
> Feeling squeamish about changing the core language isn't the sole
> prerogative of recovering Java programmers :-)  There's still no good
> answer to the question of how to do it safely and in a way that does
> not risk conflicts, though there are various "better practices".  My
> favorite is "extend", which lets you confine changes to particular
> objects.  That's not always very efficient, though.

Actually that's my core concern with this kind of thing. Ruby isn't
the fastest language out there. Patching base classes could be pretty
bad for performance in some cases, although in practice it seems to
work out pretty well.

I just tried something:

Fixnum.class_eval do
  def +(number)
    self - number
  end
end

It blew up my irb.
Raj S. (Guest)
on 2007-03-15 01:19
(Received via mailing list)
Giles B. wrote:
> I just solved a problem by adding an instance method to String.
>
> It makes for very elegant code elsewhere within the application.
>
> Yet I can't shake the feeling I've done something dirty.
>
> I think there needs to be a group like "Recovering Java Programmers
> Anonymous" or somehting.
>
I've added instance methods to both String and Array.  I didn't realize
that I should feel dirty about it.

Raj
Chad P. (Guest)
on 2007-03-15 01:45
(Received via mailing list)
On Thu, Mar 15, 2007 at 08:19:20AM +0900, Raj S. wrote:
> I've added instance methods to both String and Array.  I didn't realize
> that I should feel dirty about it.

I guess you weren't raised Catholic^H^H^H^H^H^H^H^Hon Java.
Rob S. (Guest)
on 2007-03-15 04:06
(Received via mailing list)
On 3/14/07, Giles B. <removed_email_address@domain.invalid> wrote:
> I just solved a problem by adding an instance method to String.
>
> It makes for very elegant code elsewhere within the application.
>
> Yet I can't shake the feeling I've done something dirty.
>
> I think there needs to be a group like "Recovering Java Programmers
> Anonymous" or somehting.

I worked in Java for 5+ years, and am coming up on my one year
anniversary on working in Ruby professionally.  I *still* think adding
methods to core classes should be done very selectively, and only in
cases where that method is truly useful in a wide variety of contexts.
 So if adding "foo" to String just makes my code cleaner in one spot
where its called, but I know I probably won't use "foo" anywhere else,
then I'll go with the less elegant solution of a helper method instead
of extending a builtin.

Note that I"m speaking of a larger Rails project with multiple
distributed developers - if its just you and a small side project then
hack up the core classes all you want.  =)

- Rob
James G. (Guest)
on 2007-03-15 04:18
(Received via mailing list)
On Mar 14, 2007, at 9:06 PM, Rob S. wrote:

> I worked in Java for 5+ years, and am coming up on my one year
> anniversary on working in Ruby professionally.  I *still* think adding
> methods to core classes should be done very selectively, and only in
> cases where that method is truly useful in a wide variety of contexts.

...and...

> Note that I"m speaking of a larger Rails project with multiple
> distributed developers - if its just you and a small side project then
> hack up the core classes all you want.  =)

There's quite a bit of irony here my friend.  Rails ads a good size
number of methods to the core Ruby classes.  ;)

James Edward G. II
David A. Black (Guest)
on 2007-03-15 04:28
(Received via mailing list)
Hi --

On 3/14/07, Raj S. <removed_email_address@domain.invalid> wrote:
> I've added instance methods to both String and Array.  I didn't realize
> that I should feel dirty about it.

You shouldn't -- you should just be aware of the potential problems.
Mainly it's the danger of naming conflicts, if we all start
distributing code that adds methods to the core.  It's purely a
technical issue, though it's often characterized in quasi-moral terms
("great responsibilty") or stigmatized ("monkey-patching").  My
observation is that these characterizations are usually a prelude to
doing it anyway, even though they don't address the technical problems
directly.

As soon as someone figures out a way to make it work, all will be well
:-)  Actually the libraries that allow block-scoped core changes have
never been widely used, as far as I can tell.


David
Rob S. (Guest)
on 2007-03-15 05:36
(Received via mailing list)
On 3/14/07, James Edward G. II <removed_email_address@domain.invalid> wrote:
> >> Anonymous" or somehting.
> > hack up the core classes all you want.  =)
>
> There's quite a bit of irony here my friend.  Rails ads a good size
> number of methods to the core Ruby classes.  ;)
>
> James Edward G. II

True - and some of the things ActiveSupport adds are things I wouldn't
add myself, had I built Rails :).  I think most of the extensions make
sense, given the type of applications Rails are targeting.

- Rob
James G. (Guest)
on 2007-03-15 05:43
(Received via mailing list)
On Mar 14, 2007, at 10:35 PM, Rob S. wrote:

>> >> I think there needs to be a group like "Recovering Java
>>
>> James Edward G. II
>
> True - and some of the things ActiveSupport adds are things I wouldn't
> add myself, had I built Rails :).  I think most of the extensions make
> sense, given the type of applications Rails are targeting.

Exactly.  So you are more in favor of the process than you thought.  ;)

James Edward G. II
Jos B. (Guest)
on 2007-03-15 07:52
(Received via mailing list)
Hi David,

On Thu, Mar 15, 2007 at 11:27:43AM +0900, David A. Black wrote:
[snip]
> As soon as someone figures out a way to make it work, all will be well
> :-)  Actually the libraries that allow block-scoped core changes have
> never been widely used, as far as I can tell.

Are you referring to libraries like `scope-in-state'? AfaIac, these
don't do
what I want them to do, which is the ability to restrict changes made to
some
class while executing code in some other class. This is probably
expensive as
hell and non-trivial to implement. But it sure would be great to have as
it
would make Ruby a "safer" language.

Imagine if you could add String#foo to be visible within class Bar only
without having to subclass String and use it inside of Bar instead of
String
(arguably the cleanest way to make this work otherwise).

Cheers,
Michael S. (Guest)
on 2007-03-15 12:03
(Received via mailing list)
On Thursday 15 March 2007, David A. Black wrote:
> As soon as someone figures out a way to make it work, all will be
> well
>
> :-)  Actually the libraries that allow block-scoped core changes have
>
> never been widely used, as far as I can tell.

I seem to remember behavio(u)rs and fluid-let...

Michael
Rick D. (Guest)
on 2007-03-15 14:52
(Received via mailing list)
On 3/14/07, Giles B. <removed_email_address@domain.invalid> wrote:

> I just tried something:
>
> Fixnum.class_eval do
>   def +(number)
>     self - number
>   end
> end
>
> It blew up my irb.

With great power comes great responsibility!

It also might be the case in some future implementations that such a
patch might be ineffective, or intermittently effective.

For example, some Smalltalk implementations, would handle a + b under
the covers as an integer add of the two object pointers and a little
adjustment, followed by a quick check to see if the result were a
fixnum, and only send the :+ message if it wasn't.  This check can be
done relatively inexpensively due to the way in which references to
FixNums (or SmallIntegers as Smalltalk called them) are encoded.

If a number x is in FixNum range then it's encoded as a 'pointer' with
the binary value x*2+1  This means that, if the low-order bit set it's
a Fixnum otherwise it isn't. So if we have two object pointers xp and
yp, referring to the objects x and y respectively we can implement x +
y as something like:

   result = xp + yp - 1;
   if (arithmetic overflow || !(result && 1) ) {
        result = send(xp,:+,yp)
   }

Note that, if xp and yp refer to Fixnums:

   xp + yp - 1
   = (x*2+1)+(y*2+1) - 1
   = x*2 + y*2 + 1
   = (x+y)*2 + 1

which is the correct representation for the FixNum x+y

I don't know whether YARV already does this or might in the future.
This is one of the things which VM implementers tend to look for, they
'cheat' and try not to get caught in the interest of performance.

Now Matz and his team might reject some of these tricks since the
dynamic nature of ruby might make it harder not to be caught, but in
some of these edge cases, I think that case can be made that it's
probably OK since it's unlikely that anyone will actually redefine
basic arithmetic operations on core classes such as FixNum and live to
tell about it without blowing up irb or worse.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
Giles B. (Guest)
on 2007-03-15 22:15
(Received via mailing list)
On 3/15/07, Rick DeNatale <removed_email_address@domain.invalid> wrote:
> > It blew up my irb.
>
> With great power comes great responsibility!

Two quick things about that: first, I tried it in another irb, and it
worked. This gave me great pleasure, although it was definitely a
guilty pleasure. For instance:

>> 5 + 6
=> -1

What blew it up wasn't irb itself, but Wirble, which I use for syntax
coloring, tab completion, etc.

The other thing is, the great power/great responsibility thing, I
blogged about that a little while back, the "Ruby Is Spider-Man"
theory:

http://gilesbowkett.blogspot.com/2007/03/what-supe...

Really though I'm growing more comfortable with the "patch everything"
philosophy. I see more problems coming from standard OO design issues
than I do from the "extra" power in Ruby.
Luciano R. (Guest)
on 2007-03-15 23:52
(Received via mailing list)
> Really though I'm growing more comfortable with the "patch everything"
> philosophy.

I'll borrow a quote from Alan Runyan (one of the creators of Plone),
which applies to Python and but even more so to Ruby:

"Ruby is a language for consenting adults."

[ ]s
Luciano
Paulo S. (Guest)
on 2007-03-16 02:32
(Received via mailing list)
Great! Now I am feeling a bit better knowing that I am not the only one
with
a case of Java guilt.

Being a Ruby newbie myself, I had mixed feelings of joy and disgust when
I
saw a tutorial showing how Rails overrides string and numeric classes. I
am
already at a stage of acceptance and rejoice now.
Trans (Guest)
on 2007-03-16 03:50
(Received via mailing list)
On Mar 15, 1:51 am, Jos B. <removed_email_address@domain.invalid> wrote:
> Are you referring to libraries like `scope-in-state'? AfaIac, these don't do
> what I want them to do, which is the ability to restrict changes made to some
> class while executing code in some other class. This is probably expensive as
> hell and non-trivial to implement. But it sure would be great to have as it
> would make Ruby a "safer" language.
>
> Imagine if you could add String#foo to be visible within class Bar only
> without having to subclass String and use it inside of Bar instead of String
> (arguably the cleanest way to make this work otherwise).

I wrote an experimental lib a while back that let you sub in your
class for another within the scope of another module/or class. I think
it's a pretty easy way to work with this concept. Far-sight better
than the clock based approaches, IMO. The central idea is:

  class InBlanket

    # This would have a even nicer DSL.

    String = Class.new(::String) do
      def to_s; "(" + super + ")"
    end

    def tryme
      puts "three pigs"
    end

  end

  InBlanket.new.tryme  #=> "(three pigs)

This could actually be made to work fairly easily *if* literals used
the ::new methods. Unfortunately they don't. So one would have to do
back and use String.new instead of "".  I consider this a design flaw
in Ruby current implementation, though I'm sure there are
justifications for it (probably execution speed related).

In any case, I think the above is about the most elegant approach
possible for selector namespaces. Every other notation I've seen
deters me due to the spaghetti it makes of the code.

T.
Pit C. (Guest)
on 2007-03-16 18:45
(Received via mailing list)
Jos B. schrieb:
> On Thu, Mar 15, 2007 at 11:27:43AM +0900, David A. Black wrote:
>> As soon as someone figures out a way to make it work, all will be well
>> :-)  Actually the libraries that allow block-scoped core changes have
>> never been widely used, as far as I can tell.
>
> Are you referring to libraries like `scope-in-state'? AfaIac, these don't do
> what I want them to do, which is the ability to restrict changes made to some
> class while executing code in some other class. This is probably expensive as
> hell and non-trivial to implement. But it sure would be great to have as it
> would make Ruby a "safer" language.

Jos, we've talked about this two months ago on ruby-core. Maybe it's
only the syntax of libraries like "import-module" which you don't like,
but I think they can do what you want. See below.

> Imagine if you could add String#foo to be visible within class Bar only
> without having to subclass String and use it inside of Bar instead of String
> (arguably the cleanest way to make this work otherwise).

Changing the interface of import-module to something like Tom's example,
here's your use case:

   require "import-module-extended"

   class Bar

     extending(String) do
       def foo
         "the foo version of #{self.inspect}"
       end
     end

     def initialize(name)
       @name = name
     end

     def hello(name = nil)
       name ||= @name
       puts(name.foo)
     end

   end

   b = Bar.new("Jos")
   b.hello                         # => the foo version of "Jos"
   b.hello("Pit")                  # => the foo version of "Pit"

   b.hello(1) rescue puts "no Fixnum#foo"  # => no Fixnum#foo
   "Pit".foo rescue puts "no String#foo"   # => no String#foo

You can see that #foo is added to String but is only visible within
class Bar. (The implementation is a quick and dirty hack, though.)

Regards,
Pit
Pit C. (Guest)
on 2007-03-16 18:49
(Received via mailing list)
Trans schrieb:
>       def to_s; "(" + super + ")"
> This could actually be made to work fairly easily *if* literals used
> the ::new methods. Unfortunately they don't. So one would have to do
> back and use String.new instead of "".  I consider this a design flaw
> in Ruby current implementation, though I'm sure there are
> justifications for it (probably execution speed related).

Tom, what would happen in your implementation if I pass a string from
the outside to tryme? And what would happen if I use a string created in
InBlanket outside of the class?

Regards,
Pit
Trans (Guest)
on 2007-03-16 19:45
(Received via mailing list)
On Mar 16, 12:45 pm, Pit C. <removed_email_address@domain.invalid> wrote:
> > hell and non-trivial to implement. But it sure would be great to have as it
> Changing the interface of import-module to something like Tom's example,
>      end
>    end
>
>    b = Bar.new("Jos")
>    b.hello                         # => the foo version of "Jos"
>    b.hello("Pit")                  # => the foo version of "Pit"
>
>    b.hello(1) rescue puts "no Fixnum#foo"  # => no Fixnum#foo
>    "Pit".foo rescue puts "no String#foo"   # => no String#foo

I stand corrected. This is a fine interface.

T.
Trans (Guest)
on 2007-03-16 19:53
(Received via mailing list)
On Mar 16, 12:49 pm, Pit C. <removed_email_address@domain.invalid> wrote:
>
> >   end
> the outside to tryme? And what would happen if I use a string created in
> InBlanket outside of the class?

Good point, Pit. The String defined outside would not be effected.
Most data comes from the outside, so there's really no point to this
unless the incoming data is recast into the extended version
automatically (or manually?).

T.
Jos B. (Guest)
on 2007-03-17 02:31
(Received via mailing list)
On Sat, Mar 17, 2007 at 01:45:03AM +0900, Pit C. wrote:
> >class while executing code in some other class. This is probably expensive
> >as
> >hell and non-trivial to implement. But it sure would be great to have as it
> >would make Ruby a "safer" language.
>
> Jos, we've talked about this two months ago on ruby-core. Maybe it's
> only the syntax of libraries like "import-module" which you don't like,
> but I think they can do what you want. See below.

Indeed we did.

>   class Bar
>
>
>   b.hello(1) rescue puts "no Fixnum#foo"  # => no Fixnum#foo
>   "Pit".foo rescue puts "no String#foo"   # => no String#foo
>
> You can see that #foo is added to String but is only visible within
> class Bar. (The implementation is a quick and dirty hack, though.)

That's sweet! This does indeed seem to do what I'm looking for. Thanks
Pit!
And Tom, too. :-)

If I wanted this to be used inside class Baz, too, would I stick `foo'
in a
module and use `extending' with that module somehow? I need to go check
out
`import-module-extended'...

If it's a hacky implementation, how could it be cleaned up? This would
be
great to have as part of stdlib.

Cheers,
Logan C. (Guest)
on 2007-03-17 03:24
(Received via mailing list)
On Sat, Mar 17, 2007 at 01:45:03AM +0900, Pit C. wrote:
> >class while executing code in some other class. This is probably expensive
> >String
>       def foo
>       puts(name.foo)
>
> You can see that #foo is added to String but is only visible within
> class Bar. (The implementation is a quick and dirty hack, though.)
What happens if I do
class Q
  def initialize(s)
    s.foo
  end
end

class Bar
  def hello2
    Q.new("hmm")
  end
end

Bar.new.hello2

More importantly than what does happen, is what should happen?
Trans (Guest)
on 2007-03-17 04:23
(Received via mailing list)
On Mar 16, 9:23 pm, Logan C. <removed_email_address@domain.invalid> wrote:
> > >some
> > >without having to subclass String and use it inside of Bar instead of
> >     extending(String) do
> >       name ||= @name
> >   "Pit".foo rescue puts "no String#foo"   # => no String#foo
>
> class Bar
>   def hello2
>     Q.new("hmm")
>   end
> end
>
> Bar.new.hello2
>
> More importantly than what does happen, is what should happen?

It should raise an error. #foo is not defined for String in the scope
of Q. Which is why my idea doesn't work --at least not as I originally
conceived it.

Any efficient implementation of this becomes quite a problem I
imagine. Seems like it would require all objects to be references, so
they could become any other type on the fly.

T.
This topic is locked and can not be replied to.