Java guilt


#1

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.


#2

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 :slight_smile: 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


#3

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


#4

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 :slight_smile: 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.


#5

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

#6

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.


#7

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. :wink:

James Edward G. II


#8

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
:slight_smile: Actually the libraries that allow block-scoped core changes have
never been widely used, as far as I can tell.

David


#9

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. :wink:

James Edward G. II


#10

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
:slight_smile: 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,


#11

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. :wink:

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

#12

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

:slight_smile: 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


#13

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
= (x2+1)+(y2+1) - 1
= x2 + y2 + 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/


#14

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-superhero-is-your-programming.html

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.


#15

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


#16

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.


#17

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.


#18

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
:slight_smile: 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


#19

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


#20

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.