Diff of opinion on dynamic stuff

B

Bob Hutchison

I think there are two conflated issues here. First open classes and
their abuse and second dynamic method creation. I think they distinct
enough they should be considered separately.

I agree. But these issues and a few others (e.g. types, inheritance, =20
encapsulation, modules, namespaces) are often combined, or conflated, =20=

deliberately, into a single solution -- the Class. For an absolutely =20
excellent explanation of the reasoning see Bertrand Meyer's <http://=20
en.wikipedia.org/wiki/Bertrand_Meyer> Object Oriented Software =20
Construction 2nd Edition where he lays out Eiffel (which you really =20
have to try seriously before you dismiss it). For an absolutely =20
excellent experience of what happens when you relax some of this give =20=

CLOS -- or Ruby -- a try.

Considering open classes, I find many of the conventions used in
Rails, once they are understood, simplify the resulting code. Given
this, it is worth pointing out that Rails is fairly unique in Ruby
development being a mainstream library that does modify base classes.
Additionally very few of the enhancements to the base classes are
"non-obvious" even a non-programmer will recognize the purpose of
item.pluralize. It is arguable and I would not disagree that this is
still thin ice. Using different Ruby libraries may cause issues=97it
would be good if such changes could be better scoped. Still in
practice I have encountered none of the sort of problems I have would
expected. And unit tests are still the best medicine

Xampl also modifies existing classes. It will, optionally, write a =20
file that shows you exactly what it did, but the changes are very =20
uniform and predictable. =46rom what I've seen of Rails the changes it =20=

makes are also uniform and predictable (I don't know if it will write =20=

a file). Furthermore, it looks as though the demands of Rails and =20
xampl are independent. I've found that the biggest problem comes from =20=

putting requirements on the inheritance structure of extended =20
objects. Ruby lets you side-step that problem very neatly (Java does =20
not -- it is horribly complex what you have to do).

Unit tests are necessary I think. But they are not sufficient. Back =20
in the Old Days when we worked in assembler, there was this horrid =20
practice of 'patching' that worked by loading the original code then =20
over-writing parts, maybe just a few bytes, of that with new code =20
that fixed problems. This was a nightmare. Assembler is bad enough, =20
patches are over top. Now, in Ruby, what if some clever 'programmer' =20
decides to fix a problem by replacing a method without removing the =20
original from the source? Though this is better than the assembler =20
situation it is still outrageous... well, at least I'd be outraged =20
not to mention enraged :) And unit tests won't detect this behaviour.

Never-the-less, I *like* open classes. They are very powerful, very =20
useful.
The second issue of dynamic method generation (which I think was the
meat of the above quote) seems more like a documentation issue than
anything else. Consider a different framework that used a data file to
code generate a large number of access methods into a database,
similar to the functionality which is dynamically generated within
ActiveRecord=97would this be the monkey patching that is so troubling?
Similarly, while it can take some acclimation, who cannot understand
code like:

item_list =3D Item.find_all_upc(upc)

Yes, you would look long and hard to find this particular method in
the API, but once the convention is understood (as it should be by
anyone who has developed in Rails for more than a day or two) it is
very intuitive.


A little more than just a documentation issue I think, but certainly =20
related. What if a soon-to-be-unemployed 'programmer' built up a =20
string in memory, maybe computing the name somehow, then evaled it? =20
The fact that the original method is also generated, and that you =20
know that because Rails is consistent, will only make it harder to =20
even recognise what is happening.

(I still like this capability, don't forget, just pointing out a =20
stupid thing to do)
In the end, I think it is a matter of trust. Any programming language
worth using, can be used poorly. Ruby and Python are no exception in
this regard. Writing good code which by definition is maintainable
code by both first and second generation coders is difficult. Rails
uses much of the power of the Ruby language to map the code to the
problem domain (database driven web applications).

I agree. But a lot of people think programmers need safety shields.
As always the devil is in the details. I would be very curious which
aspects of Ruby/Rails development in particular anyone thinks will be
a long term maintenance issue.

Not the code generation part I think, in fact, it might turn out to =20
be a major boon to maintenance (fix it in one place kind of thing). =20
I'd be more concerned with having to re-factor a controller and =20
breaking a bunch of URLs (but I don't know Rails well enough to know =20
if this is actually a possible issue).

Cheers,
Bob
 
P

Patrick Hurley

I agree. But these issues and a few others (e.g. types, inheritance,
encapsulation, modules, namespaces) are often combined, or conflated,
deliberately, into a single solution

These are powerful tools and their power increases by using them
together, I suppose that the danger (the point of the article) may as
well, but you would have to show me a case. The "danger" issues appear
to be specific case issues and not with their combined use.
...in Ruby, what if some clever 'programmer'
decides to fix a problem by replacing a method without removing the
original from the source?

Trust :)
It is possible to intentionally write code to pass a unit test and
later fail. Of course you could argue that some higher level set of
tests should fail and start a "arms race" with your devious
programming the and rest of the responsible coders writing unit tests.
Of course you could just take the poor misguided soul aside and
explain the error of their ways -- show them how to write a proper
unit test for the original method that was in error and then correct
it. Of course if you could just fire the numbnut too :) If you work
in an environment where you cannot trust the developers powerful tool
may be better replaced with straight jackets -- as always select the
best tool for your environment and task.
A little more than just a documentation issue I think, but certainly
related. What if a soon-to-be-unemployed 'programmer' built up a
string in memory, maybe computing the name somehow, then evaled it?
Trust...

I'd be more concerned with having to re-factor a controller and
breaking a bunch of URLs (but I don't know Rails well enough to know
if this is actually a possible issue).

Internal to the application good coding in Rails uses url_for type
helpers that will generally deal with all of this correctly. External
to the app, if it is a concern routes can be pretty easily manipulated
-- but this is a good point for externally linked sites, action names
are "pushed" into your URL interface by default and they should be
carefully considered.
Cheers,
Bob

Happy Holidays and thank you for taking the time to respond
pth
 
B

Bob Hutchison

Yes, the equivalent of "method_missing" has been used for many things
in Smalltalk. Glorifying in how we can hack "doesNotUnderstand:"
avoids having to admit that there's been a problem with the language.

The problem being: in Smalltalk the language there is no explicit way
in the language to add a method to a class at runtime?

Maybe so, but the Smalltalk *environment* allows the programmer to do
exactly the same thing as the browser or debugger at runtime (though
only on a class level). In some implementations, there is a method
that changes an object's class, and that combined with the ability to
create a new class at runtime... (well, this is hard to manage, and
some implementations will, effectively, only redefine the parent
class of an object). This excessive use/dependency on
doesNotUnderstand is not necessary in Smalltalk.

Isn't re-opening a class very similar to some of the better methods
in the paper below? At the very least, the associated problems are
similar :)

What are the Python folks doing as an alternative?
 
J

James Britt

F

Florian Groß

Brian said:
There seems to be alot of industry inertia on static time tools. Better
runtime tools would make a dynamic language such as Ruby more mainstream.

A number of people have proposed that the runtime tools can work with good
unit tests in place to exercise all of the code paths.

The breakpoint library is a good start but there is more potential. For
example, a tool that analyzes the runtime paths and graphs an object's
dependencies would be nice.

The ruby-breakpoint library is not yet everything I would like it to be.

I might even morph it into a Smalltalk style IDE in the future.

However, as soon as I have that PowerBook I owe myself I will work on
finishing the basic functionality of the GUI client. After that we'll
see what else is possible. I have high hopes on GTK2 and Glade and all
that. It makes it easy to keep the code in a clean and sane state.

Here's a recent screenshot of what already works:

http://flgr.0x42.net/breakpoint/cyclic-threads.png

The code visible on there is the code of the GUI itself. It is written
in wxRuby and ugly. wxRuby tends to be in the way way too often.

I want this to work well on OS X, though, which means that it should run
without an X server. There's a port of GTK going on that should achieve
just that. I'd like to test this, but am still missing the PowerBook. It
should reach me soon enough, though...

And Ruby-GTK just rocks.

The more help I can get on this the better. But I'm also interested in
other development tools that actually make use of Ruby's dynamic nature
instead of working around it... (For example the method name completion
in jEdit's Ruby plug in is insanely clever. We need more of that kind of
thing!)
 
F

Florian Groß

In Ruby, I see it differently. This is where I start having trouble
expressing it. It's a kind of wish that the gravitational forces be
aligned differently: instead of showing one's strength by pulling
away from the vortex, perhaps the powerful things in the language
could be *used* in productive ways, so that one falls *toward* them,
but without danger.

Wrapping unrubyish things behind a rubyish interface so other people can
do things in the Ruby way without endangering themself?

Of course this doesn't work when the very thing you are trying to do is
unrubyish and not just its implementation.

Oh, and I didn't define "rubyish" and its opposite on purpose because I
can't.
 
F

Florian Groß

Ryan said:
And now we have another weapon in the Python vs Ruby war:

Python: Dull
Ruby: Sharp

Heh, and suddenly the name C# starts making sense when comparing it to Java.

Not meaning to start a language war here either. I don't like Java, but
will let people use it. Hell, I even have to use it myself.
 
C

Chad Perrin

=20
Wrapping unrubyish things behind a rubyish interface so other people ca= n=20
do things in the Ruby way without endangering themself?

I don't think that was the intent of that statement at all.

--=20
Chad Perrin [ CCD CopyWrite | http://ccd.apotheon.org ]

unix virus: If you're using a unixlike OS, please forward
this to 20 others and erase your system partition.
 
D

dblack

--8323328-871052297-1135430107=:27488
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-871052297-1135430107=:27488"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-871052297-1135430107=:27488
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

I don't think that was the intent of that statement at all.

You're right: it wasn't :)

I think the best example is still the idea of something along the
lines of Ruby Behaviors or selector namespaces -- that is, a way to
make changes to core Ruby that are block- or file- or
namespace-scoped. (Ruby Behaviors was my attempt; there have been
others, and selector namespaces is a possible way this kind of thing
might happen in Ruby 2.) The idea is to harness the power, rather
than look at it as something that only serves the purpose of not being
used.

Basically it seems to me that if a language is designed with this kind
of power, and it's unuseable (or nearly so), that has to mean that the
design doesn't make sense. I am convinced that Ruby's design makes
sense. I think it just hasn't been fully explored and exploited.

Mind you, there are several "Behaviors"-like libraries (better written
than Behaviors, in fact), yet I don't personally know of anyone who
uses them. So maybe the demand for this isn't so great... but I
continue to believe that if there were some way to make limited-scope
core changes built into the language, it *would* be used. And it
would take a lot of pressure off the RCR process :)

Anyway, that's an example -- for me probably the best one -- of what I
mean by finding ways to fall *toward* the power of the language,
instead of constantly pushing away from it.


David

--=20
David A. Black
(e-mail address removed)

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
--8323328-871052297-1135430107=:27488--
--8323328-871052297-1135430107=:27488--
 
I

Isaac Gouy

Bob said:
The problem being: in Smalltalk the language there is no explicit way
in the language to add a method to a class at runtime?

Adding a method to a class at runtime is trivial, simply send the
message "compile: aMethodSourceString" to the class.

Integer compile: 'plus: anInteger
^self + anInteger'


afaict Over the years Smalltalk has accumulated a bunch of really
clever programming techniques to work-around the lack of meta protocols
for controlling message passing.

afaict CLOS provides directly what Smalltalk can only accomplish
indirectly - so we should celebrate "doesNotUnderstand:" trickery as
clever programming rather than clever language design.
 
I

Ian Bicking

Drew said:
Let me preface this post by saying that I'm no Ruby expert. I like it.
It's fun. But I won't claim extensive knowledge on it.

So when this guy blogs about a Python quality that he feel is better
than a Ruby quality:

It's the second generation that's going to be less enthused,
that's going to stare in bafflement at these classes that
mysteriously spawn methods, and trying to figure out what's
going when there's an exception in dynamically generated
code. You can monkeypatch code in Python pretty easily, but we
look down on it enough that we call it "monkeypatching". In
Ruby they call it "opening a class" and think it's a cool
feature. I will assert: we are right, they are wrong.

-- http://blog.ianbicking.org/theres-so-much-more-than-rails.html

I am curious what this means. Is Python against dynamic stuff? And
Ruby for it? And so we just agree to disagree? Or do I misunderstand?

There's some inaccurate ideas of Python in this thread, so I just
thought I'd chime in with a followup. You can open a class in Python
just fine (except for some select built-in classes which are closed
except in subclasses, like int, list, dict). Opening a class in Python
does not look as nice as in Ruby, and is used less often. In Python it
looks like this:

class Foo(object):
pass

def new_method(self, blah): ...
Foo.new_method = new_method

You can also open instances in Python, replace objects with a delegate
or completely different implementation, and lots of other things, many
of which are very bad ideas. There was also some mention of
method_missing in the thread, and I can assure you that it is present
in Python as well (__getattr__) and used fairly often.

My criticism isn't about what you *can* do in either language -- both
languages are quite open in this respect. Instead it is about what the
community and the language itself encourage you to do (in this case
Ruby encourages opening classes by making the syntax appealing, and the
community encourages it because examples of opening a class are fairly
common). In Python I consider opening a class to be a kind of code
smell (http://xp.c2.com/CodeSmell.html) -- but smelly code happens,
and the entire point of code smell is that a technique might *suggest*
problems in code, but does not *necessarily* mean that the code is bad.
The code might just be tackling a complex problem, or working around
problems in other code.

In a dynamic language like Ruby or Python we have to be very aware of
code smells because that's a big part of what keeps us sane. In both
languages there are techniques that look fine, but experience shows us
are dangerous or indicative of misdesign. Here I'm highlighting a case
where opinions on design differ between the communities. It's easy to
tell they differ *because* the technique is available in both
languages.

Also, to generalize, it seems that the Ruby community is perhaps less
sensitive to code smells or more tollerant of magic compared to the
Python community, which I guess was my larger point. Though I also
think that the specific case of opening a class is important enough
that it's also worthy of discussion, but this thread doesn't seem to
have much discussion of that particular issue. If you have a sharp
tool it is good to discuss what the appropriate use of that tool is --
sharp tools are only safer than dull tools if you use them correctly!

Ian
 
A

Austin Ziegler

Also, to generalize, it seems that the Ruby community is perhaps less
sensitive to code smells or more tollerant of magic compared to the
Python community, which I guess was my larger point.

Is it less sensitive to code smells, or is it something that isn't
considered a code smell in Ruby? I think that the Ruby community is as
... rough on code smell as any community, but we consider different
things smelly than the Python community does.

I think that's where some of the resistance to your points come in; to
the community at large, it is not necessarily considered bad to write
something that essentially opens classes (or objects) again. See my
own Transaction::Simple for an example -- it injects its functionality
into any class that requests it. In Ruby, that's definitely not code
smell. In Python? I don't know.

-austin
 
I

Ian Bicking

Austin said:
Is it less sensitive to code smells, or is it something that isn't
considered a code smell in Ruby? I think that the Ruby community is as
.. rough on code smell as any community, but we consider different
things smelly than the Python community does.

It's a little of both -- clearly there's some awareness among Ruby
programmers that opening classes introduces some possible issues. And
the "sharp tools" comments imply that there's potential to cut
yourself, but people feel that's okay. There's always a danger to any
technique; the question is how much danger is okay, depending on how
complex the problem at hand is. I get a sense that prevailing opinion
in the Ruby community accepts a balance with more danger than in
Python. Neither language forces you to be careful or not; in both you
could do explicit (runtime) type checking, or you can generate source
willy-nilly, or anything in-between.

Also, there's the issue about what is smelly at all. Of course,
anything that is unusual is a bit smelly, so there's a circular
justification; opening a class is smelly in Python because people don't
do it, and people don't do it because it is smelly. But just because
idioms are different doesn't mean that there isn't *any* commonality --
in both languages you are signficantly affecting code that isn't
"yours".
I think that's where some of the resistance to your points come in; to
the community at large, it is not necessarily considered bad to write
something that essentially opens classes (or objects) again. See my
own Transaction::Simple for an example -- it injects its functionality
into any class that requests it. In Ruby, that's definitely not code
smell. In Python? I don't know.

In Python, probably with a delegate, though multiple inheritance or a
mix-in would also be possible. Also, I think there's something very
different about a class that pulls in functionality, from code that
pushes functionality into a class that might not be expecting it. As I
said, there's room for discussion -- there's probably very useful rules
of thumb that could be offered about what's a good use of this sort of
feature, and what's bad.

Ian
 
S

Sky Yin

------=_Part_46276_23365721.1135813190564
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

See my
own Transaction::Simple for an example -- it injects its functionality
into any class that requests it. In Ruby, that's definitely not code
smell. In Python? I don't know.

Looks like AOP-style feature. AOP is definitely powerful though there
was a debate
<http://www.theserverside.com/news/thread.tss?thread_id=3D30154>on its
potential of being dangerous. Even strong-type language Java has several AO=
P
implementations, some of which modify byte-codes on the fly (poor java guys
don't have open class). Not to mention the usage in Rails (ex.
before_filter, acts_as_*).

I feel that Ruby is more implicit than Python in style, which is actually
similar to our natural languages, though we may sometimes misunderstand eac=
h
others.

------=_Part_46276_23365721.1135813190564--
 
D

Devin Mullins

Ian said:
Austin Ziegler wrote:



It's a little of both -- clearly there's some awareness among Ruby
programmers that opening classes introduces some possible issues. And
the "sharp tools" comments imply that there's potential to cut
yourself, but people feel that's okay. There's always a danger to any
technique; the question is how much danger is okay, depending on how
complex the problem at hand is. I get a sense that prevailing opinion
in the Ruby community accepts a balance with more danger than in
Python.
Well, I can think of two applicable "dangers," off the top of my head:
the danger of coding the wrong thing (i.e. bugs), and the danger of
taking to long to do it (i.e. un-maintainability) (and, of course,
they're related). Many factors play a role in this, including unit
tests, coding skills, code complexity, the language semantics at hand...
And I think Rubyists are just tackling those two dangers with a
different combination of tools than the Pythonistas -- not saying that
"more danger is okay."

Devin
 
B

Brian Takita

------=_Part_90459_26706014.1135969645749
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

One thing that Open objects are useful for are creating
"seams<http://c2.com/cgi/wiki?SoftwareSeam>"
and making the object easier to test. Bearing this in mind, systems that us=
e
open objects can be made more reliable than systems that dont.
 

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
474,201
Messages
2,571,049
Members
47,654
Latest member
LannySinge

Latest Threads

Top