Ideas on "Why Living Dangerous can be A Good Thing" in Ruby?

G

gwtmp01

Are you saying that when Model.find_by_city is executed, the model
looks at
the database, discovers there's a city column, and on the fly
constructs a
method to search the table by city?

I think Hal already answered this, but yes. If your class defines
the instance method 'method_missing' then Ruby will call it when it
can't
find a method definition. It would look something like this (not
tested):

class Model

def method_missing(method_name, *args)
if method_name.to_s =~ /^find_by_(.*)/
# respond to find_by call
else
super # results in standard method not found exception
end
end

end

(Note that the first argument to method_missing is an instance of
Symbol, not
String so you need to call to_s on it in order to compare it to the
regular expression. What is the difference between a Symbol and String
you ask? Um, read the archives.)

This feature of Ruby's method dispatch protocol allows a class to
implement methods on demand. It can even install a definition for
the missed method so that the *next* time it will be called directly
instead of being intercepted by method_missing.

Very handy.


Gary Wright
 
G

Gregory Brown

Interestingly, <finish me later> is, in a sense, what yielding
implies.

But is that yet another piece of the puzzle? Is the fact that ruby
can pass around blocks of codes as just another object part of what
makes it suitable for metaprogramming?

When does plain old dynamicity cross the line to become 'metaprogramming'?
That's the million dollar question we've yet to answer :)
 
G

Gregory Brown

Only a class that specifically supported that kind of behavior
would allow such a thing. See the 'ostruct' (OpenStruct)
library. Its author created it mostly as a toy, I think, but
it has been used in many situations. (I would not personally
suggest that *all* objects should behave that way.)

Not all objects, but if your goal is to hold a ton of 'never before
seen' attributes, it certainly does help.

I had this exact issue with Ruport, and created a sort of abstract
node for a tree structure, using OStruct. See it here:

http://www.oreillynet.com/ruby/blog/2006/01/so_wrong_its_almost_right.html

Probably a bad idea for most things, but it cut me about a 100 lines
in Ruport :)
 
J

J. Ryan Sobol

Indispensable uses of Ruby meta-programing.

1) Module.attr and friends are probably the simplest (and strongest)
uses that highlight the advantages of meta-programming.

2) Rails' ActiveRecord.

3) Dwemthy's Creature class. http://poignantguide.net/dwemthy/

When boiled down, Dwemthy's Creature class creates a domain-specific
mini-language that is actual Ruby code.

I'm pretty sure someone else brought up domain-specific languages in
this thread, but here are some links to learn more about them.

http://en.wikipedia.org/wiki/Domain-specific_language
http://en.wikipedia.org/wiki/Domain-
specific_language#Advantages_and_Disadvantages_of_DSLs

DSL's are used everywhere: in Sendmail configuration files, Windows
resource files, World of Warcraft UI scripting, etc. One obvious
advantage of embedded mini-languages, like sub-classes of Creature,
over external ones, like configuration files, is the ability to apply
Ruby's tools, like the irb, directly on the language.

~ ryan ~
 
D

Donkey Agony

I think Hal already answered this, but yes. If your class defines
the instance method 'method_missing' then Ruby will call it when it
can't find a method definition. It would look something like this
(not tested):

class Model

def method_missing(method_name, *args)
if method_name.to_s =~ /^find_by_(.*)/
# respond to find_by call
else
super # results in standard method not found exception
end
end

end

Fascinating. Especially the commented "respond to find_by call" part.
This feature of Ruby's method dispatch protocol allows a class to
implement methods on demand. It can even install a definition for
the missed method so that the *next* time it will be called directly
instead of being intercepted by method_missing.

How does it do that? Or better, how does *one* do it -- briefly? (I
haven't dug into the Rails code yet to see how David does it.)
 
G

Gregory Brown

I mean, here you have a black box that a few moments from now may not
be a black box anymore! It may turn green... It may pop out at you
like those fond memories of the jack-in-the-box. You look at it, prod
it, it isn't reliable (you posit), it doesn't come up like the sun in
the morning every day, and start to feel there's some deep and dark
sinister purpose waiting to be unleashed. This program, this thing,
suddenly feels like almost sort of a Pandora's box. In that moment of
inspiration, you quickly walk away feeling better about yourself for
suggesting another, more 'stable', language that you can use. The CIO
will be proud :)

At least, that was my first impression. That, until I started seeing
how impressive not only the coding practices were, but also the
incredible knowledge base in the Ruby community. Not to mention how
it has made my life a bit easier.

I'd like to quote this snippet as the beginning of my article, is that okay=
?

This brings up an interesting point though. In Ruby, idioms are more
than just 'good practice'. They really do matter, because they are
our biggest sense of 'security'. This of course leaves the
responsibilities in the hands of the coders, but from my experience,
the majority of the well known applications adhere to good style, and
their developers are consistant at being idiomatic in their
application design. The same can not necessarily be said for the
majority in other languages.
 
H

Henrik Martensson

If someone can show me an advantage to adding methods and instance variables
in real time, and that advantage can't be realized with normal OOP
techniques, I'll keep an open mind. But unless it offers me a unique benefit
that I need, I wouldn't do it.

I recently wrote some code where I had to retrieve an attribute from a
REXML attribute list based on its name and namespace. The REXML
attribute list does have a method for retrieving attributes based on
namespace prefix and name, but this is not very useful. A namespace
aware XML processor, such as an XSLT processor, can, without breaking
any rules, change prefixes at will.

I couldn't just subclass the attribute list, because the REXML parser
would not use my subclass when building a node tree from an XML
document. However, I could do this:

module REXML
class Attributes
def get_attribute_ns(namespace, name)
each_attribute() { |attribute|
if name == attribute.name &&
namespace == attribute.namespace()
return attribute
end
}
nil
end
end
end


Which enabled me to write code like this:

actual_attribute =
actual_attributes.get_attribute_ns(expected_namespace, expected_name)

I could have solved the problem with an external helper class instead,
but that would, in my opinion, have been a clumsier solution.


/Henrik
 
E

Eivind Eklund

I mean, my general advice when it comes to ruby when asked about
security is that I basically respond, "There is none, but it's not as
bad as you'd expect. Write proper test suites, code responsibly, and
make sure you nail down those edge cases. Continuous integration is a
must, and idiomatic code with proper style will help make the API
less likely to cause damage (such as the use of ! and other
indicators).

There's documentation for how to do good APIs here:
http://rpa-base.rubyforge.org/wiki/wiki.cgi?GoodAPIDesign

I hope that's useful; feel free to edit and add/change/add discussion.
However, to the outsider, this is only an explanation of "how" to
overcome the apparent "flaw". I'd like to do as good a job I can of
explaining why it isn't a flaw, when practiced correctly.

Let's look at it as a cost/benefit analysis. The cost of declaring
variables and types end up as roughly half the code size. That's
twice the amount to write, and, more importantly twice the amount to
read, twice the amount of places to change when refactoring, etc. It
also means that there's a lot of things we can't do, because we are
"protected" from it.

At this cost, the type and variable declarations had better give us a
lot. In practice, I find that they give me very little, bug wise:
Maybe 5% of my simplest bugs are detected by them. The advantages I
get are in the speed of the compiled code, and as documentation.=20
However, these benefits are too small to be worthwhile for the size
projects I presently do (one and two person projects).

I've implemented a system for doing run time checks of type
declarations, it's available from RPA (as types) and from
http://people.freebsd.org/~eivind/ruby/types/ This allows very
flexible type checks for Ruby programs, adding whatever amount of type
discipline you want. In practice, I found this to just get in the way
- it detected very few bugs, and added more stuff to change when I did
refactoring.

Eivind.
 
D

dblack

Hi --

Hi David,

I don't know for sure, because when I read about this stuff my first reaction
was "I'm not gonna do that!"

I got the impression I could do this:

myclass = MyClass.new
myclass.never_seen_before_attribute = 5

As I said, I didn't research it because I considered its use to be a negative,
but stored it in the back of my mind in case I had to maintain code like
that.

I think you mean method_missing. It has nothing to do with instance
variables; it's just a hook or callback that you can define to
intercept calls to non-existent methods. What you do at that point is
up to you. You can also just not define it, in which case a call to a
non-existent message will raise an exception.

There's nothing inherently dangerous or non-deterministic about
method_missing. It's basically a control-flow technique.


David

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

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
 
D

dblack

Hi --

But is that yet another piece of the puzzle? Is the fact that ruby
can pass around blocks of codes as just another object part of what
makes it suitable for metaprogramming?

When does plain old dynamicity cross the line to become 'metaprogramming'?
That's the million dollar question we've yet to answer :)

It's not that central a question to me. In my own work with Ruby, I
can go from one month to the next without ever thinking about what
metaprogramming is, or whether or not I'm doing anything that people
would put in that category -- whereas thinking about the dynamic
nature of Ruby I've always found not only interesting but
enlightening.

I definitely don't think that metaprogramming is an extreme or higher
form of dynamism. It's just a meta form of programming :)


David

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

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
 
D

dblack

Hi --

This brings up an interesting point though. In Ruby, idioms are more
than just 'good practice'. They really do matter, because they are
our biggest sense of 'security'. This of course leaves the
responsibilities in the hands of the coders, but from my experience,
the majority of the well known applications adhere to good style, and
their developers are consistant at being idiomatic in their
application design. The same can not necessarily be said for the
majority in other languages.

I agree -- really "Ruby" in the sense we're talking about is more than
just the language; it's also the coding practices, and the fact that
there are ways (including, but not limited to, discussion with other
Rubyists) of making good decisions about what to do.

I have to say, I'm quite surprised that the image of Ruby that's
emerging in this thread is, at least in large part, of a sort of
mine-field that we all have to tiptoe our way through -- as if the
language is a malevolent force that we write programs in spite of, and
in triumph over, rather than in harmony with. I've never perceived it
that way, and I wish I could find the words to turn the tide for
others.

I guess it comes down to this: worrying that something like dynamic
method redefinition is going to "bite" you, or "shoot you in the
foot", or whatever, at random times, without warning, is a bit like
worrying that your C program is going to erase all the files on your
hard drive. If you don't want it to, don't tell it to, and it won't.

Most of the real issues in this realm have to do with modifying core
classes. The main reason not to do this is that if someone else uses
your code as part of a program, your changes will affect their code
too. Under circumstances where that can't happen, there's no reason
not to.

Meanwhile, other dynamic-programming things -- like defining
method_missing, creating classes batch-wise, whatever -- are cut from
exactly the same cloth as the Ruby that interprets your script in the
first place. They're an opportunity to think expansively about what
you can do.


David

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

"Ruby for Rails", from Manning Publications, coming April 2006!
http://www.manning.com/books/black
 
T

Todd

Gregory Brown wrote:

[snippet]
I'd like to quote this snippet as the beginning of my article, is that okay?

Sure, whatever you think is best for your article.
This brings up an interesting point though. In Ruby, idioms are more
than just 'good practice'. They really do matter, because they are
our biggest sense of 'security'. This of course leaves the
responsibilities in the hands of the coders, but from my experience,
the majority of the well known applications adhere to good style, and
their developers are consistant at being idiomatic in their
application design. The same can not necessarily be said for the
majority in other languages.

Well said.

OT, why did my original post show up on this group three times? I seem
to be having an issue with 3 lately. Hmmmm...

Todd
 
S

Steve Litt

I guess it comes down to this: worrying that something like dynamic
method redefinition is going to "bite" you, or "shoot you in the
foot", or whatever, at random times, without warning, is a bit like
worrying that your C program is going to erase all the files on your
hard drive. If you don't want it to, don't tell it to, and it won't.

To get Ruby to do bad stuff, you need to enunciate quite clearly that you want
it to do something bad. To get C to do something bad, a muffled mumble could
be interpreted (compiled :) by C to do something bad.

Nobody's infallable. C is much more unforgiving of programmer error than Ruby.

SteveT

Steve Litt
http://www.troubleshooters.com
(e-mail address removed)
 
T

Todd

Todd said:
Gregory Brown wrote:

[snippet]
I'd like to quote this snippet as the beginning of my article, is that okay?

BTW, I should mention that using a quote like that may -- to your
intented audience -- sound a bit pretentious as the start of an
article. You need a lead-in for something like that. Well, you need
most everything that came beforehand in this thread, or at least a
summary of it.

Todd
 
I

Isaac Gouy

Eivind said:
There's documentation for how to do good APIs here:
http://rpa-base.rubyforge.org/wiki/wiki.cgi?GoodAPIDesign

I hope that's useful; feel free to edit and add/change/add discussion.


Let's look at it as a cost/benefit analysis. The cost of declaring
variables and types end up as roughly half the code size. That's
twice the amount to write, and, more importantly twice the amount to
read, twice the amount of places to change when refactoring, etc. It
also means that there's a lot of things we can't do, because we are
"protected" from it.

At this cost, the type and variable declarations had better give us a
lot. In practice, I find that they give me very little, bug wise:
Maybe 5% of my simplest bugs are detected by them. The advantages I
get are in the speed of the compiled code, and as documentation.
However, these benefits are too small to be worthwhile for the size
projects I presently do (one and two person projects).

Does a language with type-inference require as many type and variable
declarations as a language without type-inference?

Is the C++ type system the same as the SML type system?

Will programmers who passively suffer compiler type-checking detect as
many bugs as programmers who actively use 'type-full' programming as a
checking-tool?
 
G

Gregory Brown

Gregory Brown wrote:

[snippet]
I'd like to quote this snippet as the beginning of my article, is tha=
t okay?

BTW, I should mention that using a quote like that may -- to your
intented audience -- sound a bit pretentious as the start of an
article. You need a lead-in for something like that. Well, you need
most everything that came beforehand in this thread, or at least a
summary of it.

I plan to go in reverse of that ;) I *want* it to sound pretentious,
because your observation is the common one you hear from someone who
hasn't done much ruby or seen it actively working. I'm not sure if
I'm going to use it at this point, but I thought it was a good example
of the common concerns.
 
G

Gregory Brown

I have to say, I'm quite surprised that the image of Ruby that's
emerging in this thread is, at least in large part, of a sort of
mine-field that we all have to tiptoe our way through -- as if the
language is a malevolent force that we write programs in spite of, and
in triumph over, rather than in harmony with. I've never perceived it
that way, and I wish I could find the words to turn the tide for
others.

David, if it wasn't fully clear, I was being somewhat facetious when I
was talking about "Living Dangerous". However, I think I will use the
title "The Open Nature of Ruby" because it sounds a lot more positive
and friendly.

You make a wonderful point. I doubt very many people who are doing
ruby actively day to day think "Oh my god... what havoc is this code
going to unleash". In fact, from my experience, Ruby has seemed to
comfort me and give me confidence more than most any other language.
 
G

Gregory Brown

It's not that central a question to me. In my own work with Ruby, I
can go from one month to the next without ever thinking about what
metaprogramming is, or whether or not I'm doing anything that people
would put in that category -- whereas thinking about the dynamic
nature of Ruby I've always found not only interesting but
enlightening.

Same here. My concern is with the fear it seems to cause in people
migrating from the static world. I honestly am very lazy and simply
do not want to argue the static vs. dynamic typing, early binding vs
open class structure, compile vs. runtime arguments anymore. So, I'm
trying to write a well formed article I can point people to ;)
I definitely don't think that metaprogramming is an extreme or higher
form of dynamism. It's just a meta form of programming :)

well said.
 
G

gwtmp01

My concern is with the fear it seems to cause in people
migrating from the static world.

What is being feared? I'm still not entirely
sure I understand what specific concerns lead to insecurity
about using a dynamic language like Ruby. I'll bet if you
did some search of the literature you might find some
useful history on this debate as it relates to Smalltalk
and/or CLOS.

I'm not saying there aren't valid concerns. What I'm saying
is: can those concerns be elaborated beyond some general
notion of 'fear' or 'security' and wouldn't that help construct
a more appropriate response?

Gary Wright
 
G

Gregory Brown

What is being feared? I'm still not entirely
sure I understand what specific concerns lead to insecurity
about using a dynamic language like Ruby. I'll bet if you
did some search of the literature you might find some
useful history on this debate as it relates to Smalltalk
and/or CLOS.

If you remember from our first New Haven Rubyists meeting, there was a
decent amount of tension from the Java guys in the house. People who
tend to lean on the compiler for support feel like they're going to
fall flatfaced upon entering Ruby. We know that this isn't true, but
I am not entirely sure how to address it, though this thread has given
me some ideas.
 

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,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top