Monkeypatching is Destroying Ruby

S

s.ross

been re-opened and a means to ignore it by file/path or namespace if
we
want.

This whole thing is a complex philosophical discussion about the goals
of the language and the problems that could be encountered if...

Perhaps someone could, instead of debating the theory, the impacts on
scaling, and the philosophy, come up with a patch and run it by Ruby
core for comment. Otherwise this thread could continue forever with
those who find monkey patching useful saying ... um ... "I find monkey
patching useful" and those who have issues with open classes
saying ... um ... "it's not scalable, it's surprising, it's destroying
Ruby, etc."

The arguments are out there. What it takes is a stake in the ground (a
patch) that demonstrates some "better way" that doesn't cause Ruby to
break existing applications.

FWIW, I'm in the first camp, and feel Ruby does just fine for my
needs. I understand the arguments to the contrary, but don't
anticipate them being a problem in my application space. That's not to
claim validity of either position, just disclosure of my predisposition.

Cheers,

Steve
 
A

Avdi Grimm

FWIW, I'm in the first camp, and feel Ruby does just fine for my
needs. I understand the arguments to the contrary, but don't
anticipate them being a problem in my application space. That's not to
claim validity of either position, just disclosure of my predisposition.

If that's how you personally divide things, then I'm in your camp too.
No, really.

I'm actually not very interested in any of the proposals to extend
Ruby (either with patches or with Ruby code). I'll be completely
satisfied if, as a result of this discussion, a few more people think
"oh yeah, I could do this with [inheritance|mixins|delegation|etc.],
and it would be easier than monkey patching!" when they set out to add
some functionality to an existing class.

As far as the language goes, I'm happy with Ruby the way it is.
 
R

Robert Dober

You can monkeypatch Class#freeze, as long as you get there first ;)

class Class
def freeze; end
end

class Foo
def bar; end
end

Foo.freeze

class Foo
def zap; end
end

That indeed is a truly perverse use case for MP, you have my deepest respect ;).
It is indeed an extreme example what the enabling approach can lead
to, but it is maybe not a coincidence that it was Smalltalk which
really brought up UT first IIRC?
That is something we should add into this discussion, MP might be a
danger for Ruby to be extincted (I do not believe so but just for the
sake of argument), TDD (or BDD) might save it somehow.
But there is no doubt it is not much of a relief if somebody released
something stupid in a library and now a zillion tests do not pass
anymore.

Just out of curiosity why does Class#freeze need to exist and cannot
be inherited from Object#freeze?

Cheers
Robert
 
J

Joel VanderWerf

Robert said:
Just out of curiosity why does Class#freeze need to exist and cannot
be inherited from Object#freeze?

Because Module#freeze is defined by ruby (so redefining Object#freeze
would not have the desired effect in this case).
 
E

Eivind Eklund

I would now suggest that it is the FHS that is holding us back, not
the other way around --talk about your size/momentum advantage.

Suggested reading:

http://gobolinux.org/index.php?page=doc/articles/clueless

I perfectly agree that a large part of the reason the FHS is the way
it is (and why we're using FHS or something similar on most Unix
systems) is historical momentum. I feel that's a tangent, though.

In my opinion, the core issue is that people should be able to expect
a single directory layout on a single operating system, so the
operating system owns the directory layout. If you are going to write
a package manager that works on different operating systems, it should
be able to adopt to the conventions of those operating systems, or it
hose the users of the operating systems. Users that don't care if a
package is written in Ruby, or in Python, or in C, or whatever.

I think having different operating systems - like GoboLinux, like Mac
OS X, like Windows - that experiment with different layouts is a good
thing. There may well be other layouts that work better than the
traditional one these days. I just think this is an area for
operating systems to experiment, not programming languages.

Eivind.
 
F

Florian Gilcher

Hi,

I have read all other Statements in this thread, but as it is such a
vast collection of opinions, its hard to keep track. So: if I mention
something for the second time, please ignore it ;).

I think the problem with MonkeyPatching is clear: it is a hack and
hacks tend to die soon. I am strongly opposed to use it in an official
release without thinking twice. Usually, there is a better way to
solve the problem. When browsing Rails plugins (i don't want to bash
rails, but thats an incredibly big source third-party-libraries), I
often see gruesome hacks to solve problems that could easily be solved
otherwise - because the author obviously didn't know about the right
way. Some time ago, many plugins had some implementation of
String#constantize (better, worse, the same as the Rails version).
This shows one thing:
Plugin authors are not aware of everything the language has to offer.
So they do what they do best. Which is not always good. The other side
of the problem is that the target of your patch is not written to be
extended (have a look at the "render"-Method in rails) - so you only
quick resort is a hack.
Monkeypatching is cool - if you think well an at least twice about it.

The problems with meta-programming is another one:
We love it. We advertise it as core features of the language (which -
in my book - it is not).

Take the above example: Array#to_csv

Why not CSV.from(arg)? It is cumbersome to read and we need to think
about a way to split the implementation details of from(Array) and
from(otherType) in halves. But from an OO-perspective, it makes
perfect sense: an Array doesn't have to care about the types that it
can be converted into an it is well encapsulated.

But, because we are lazy, lazy ruby programmers, we love our
object.send syntax. So we implement a shorthand method. Another
example is Object.in?(), often seen as a shorthand for
some_collection.contains?(obj) (Im not sure, but this is called
'grief', afaik). The first is nicer, the second is cleaner. Many vote
for the first - another Method in Object. Another well known Library
defines Object#should because they think of it to be nicer. By doing
this, we are slowly overloading the core-system. I like approach of
facets: they are a collection of such idioms, but they must be
switched on explicitly.
The question you have to answer for yourself when creating such a
method is: "Is it really that important?". Often I have the impression
that this question is often answered with "Yeah, its cool and its the
ruby way!"

On the other hand, those features are the ones that make the little
difference. Used correctly, open classes are a way to beautiful and
well constructed code.

It all comes boils to a matter of knowledge, experience and
discipline. We have got to be aware that many ruby developers don't
have all of those.

Greetings
Florian Gilcher <Skade>
 
J

James Gray

Some time ago, many plugins had some implementation of
String#constantize (better, worse, the same as the Rails version).
This shows one thing:
Plugin authors are not aware of everything the language has to offer.

Just to be clear, the Ruby programming "language" does not have a
method called String#constantize. It's provided by the Ruby on Rails
"framework."

James Edward Gray II
 
F

Florian Gilcher

Yes,

sorry for not mentioning. I just found that many that where developing
plugins for Rails where patching things that didn't need to be patched
or hacked in the Framework.
Thanks for the clarification.

Florian Gilcher
 
J

James Gray

Please don't top post.

Just to be clear, the Ruby programming "language" does not have a
method called String#constantize. It's provided by the Ruby on Rails
"framework."

Please reread the quote above where the poster hints that the method
is provided by a "language."

James Edward Gray II
 
F

Florian Gilcher

Please don't top post.



Please reread the quote above where the poster hints that the method
is provided by a "language."

James Edward Gray II

As i said, it was an accidential error and should read "Framework".
Programming Ruby for 5 years, I know the distinction ;).

Florian Gilcher
 
R

Robert Dober

Because Module#freeze is defined by ruby (so redefining Object#freeze
would not have the desired effect in this case).
I was not criticizing your solution(1), I only wanted to know something.

Let me rephrase my question then, why Module#freeze what has it to do
in addition to Object#freeze
Just in case you happen to know.
Thx in advance

Cheers
Robert
 
M

Martin DeMello

But, because we are lazy, lazy ruby programmers, we love our
object.send syntax. So we implement a shorthand method. Another
example is Object.in?(), often seen as a shorthand for
some_collection.contains?(obj) (Im not sure, but this is called
'grief', afaik). The first is nicer, the second is cleaner. Many vote
for the first - another Method in Object. Another well known Library
defines Object#should because they think of it to be nicer. By doing
this, we are slowly overloading the core-system.

And? There's nothing wrong with "overloading the core system" if the
end result is cleaner and more readable code. Personally, good ruby
code is all about expressiveness and readability, not proper OO
encapsulation and staying-out-of-the-core. The only real problem, as
you note, is that of conflicting extensions to the same core classes,
and care does need to be taken with that, but that's no reason to
throw the baby out with the bathwater.

One interesting thing to do is something I've seen in the Javascript
world - libraries that come with an option to install themselves in
core classes or stick to a namespace, so that you can either type
MyLib.do_something(object), or turn the option on and then do
object.do_something.

martin
 
T

Trans

Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate code
bases that have different expectations for Hash#-.

BTW, there is a reason for that. You can do:

ahash - otherhash.keys

T.
 
F

Florian Gilcher

Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate code
bases that have different expectations for Hash#-.

BTW, there is a reason for that. You can do:

ahash - otherhash.keys

T.

That does not hurt the argument. If you expect this, you are fine.
If you define or expect a different interpretation, you are in a world
of pain.

But it can be argued that you should be aware of this, especially when
you
are using Facets, which consists of a high number of such cases.

Florian Gilcher
 
T

Trans

Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate code
bases that have different expectations for Hash#-.
BTW, there is a reason for that. You can do:
ahash - otherhash.keys

That does not hurt the argument. If you expect this, you are fine.
If you define or expect a different interpretation, you are in a world
of pain.

Sure. I was just pointing out why that particular functionality was
chosen, vs. the other reasonable suggestion. That's another benefit of
using a common library --you get a lot of collective minds evolution
behind things.

T.
 
E

Eric Mahurin

[Note: parts of this message were removed to make it a legal post.]

Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate code
bases that have different expectations for Hash#-.

BTW, there is a reason for that. You can do:

ahash - otherhash.keys

I think this is the worst kind of monkey-patching - breaking existing
functionality. I didn't realize facets went to this level. Another reason
to never touch it.
 
F

Florian Gilcher

On Feb 24, 4:43 pm, Gary Wright <[email protected]> wrote:
Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate
code
bases that have different expectations for Hash#-.
BTW, there is a reason for that. You can do:
ahash - otherhash.keys

That does not hurt the argument. If you expect this, you are fine.
If you define or expect a different interpretation, you are in a
world
of pain.

Sure. I was just pointing out why that particular functionality was
chosen, vs. the other reasonable suggestion. That's another benefit of
using a common library --you get a lot of collective minds evolution
behind things.

T.

I agree. But I think facets is a bad example, because the whole
premise of facets is extending core classes. Everybody that uses it is
aware of it. ActiveSupport is much more of a problem because it is
part of a library that is not advertised as a library extending Ruby.

Whats much more problematic is a library that does arbitrary things
and extends Object and/or Module just for the sake of simplicity and
cuteness. Perhaps without letting you know and without advertising it.
I ran into that case multiple times and after another debugging
session the only thing that stays is the anger :).

I agree with the fact that everybody should write the code that he
likes. But good (public) library code does not mess with the
sentiments of other programmers too much. A nice way that was proposed
is to have an opt-in way for those behaviours. So nobody can complain
that he didn't know about this fact. For example:

==== code ====
require 'some_csv_lib'

CSV.to_csv(array) #standard way

array.to_csv #error

CSV.furry_cuteness :eek:n
array.to_csv #just fine
==== code ====

I for example don't use RSpec because it changes Object (and by that,
the testee). Thats my personal opinion. I understand everybody that
says that I'm thinking too strict. But i'm just fine with using
assert. You can do TDD without explicitly saying "should". Your
mileage may vary :).[1]

Perhaps, this is also a matter of communication from library author to
user.

Greetings
Florian Gilcher

[1]: Fine print: no, I do not wish to discuss this stance. This is
just an example. Don't even try.

P.S.: Does anybody know how I get Apple Mail to wrap after ~78
characters line width when composing a mail?
 
M

M. Edward (Ed) Borasky

Florian said:
P.S.: Does anybody know how I get Apple Mail to wrap after ~78
characters line width when composing a mail?

Translate it to Ruby and monkeypatch?

<ducking>
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top