Proposed Solutions - Was

On Tue, Feb 26, 2008 at 11:55 PM, James B. [email protected]
wrote:

That’s ridiculous.
“#{@core_feature} should be locked down!”

It’s not that these claims are entirely untrue, it’s just that, in real
life, most people simply do not encounter the alleged problems.

Code that is poorly written or does not play well with others tends to
get discarded.

James, Sometime ago Rick O. wrote this:

http://weblog.techno-weenie.net/2007/12/19/adventures-in-rails-debugging

Does ring a bell, doesn’t it? All the libraries Rick mentions in his
blog are well regarded and yet he has a problem.

From my own experience I have encountered similar problems countless
times and you know these problems are HARD to debug.

As i wrote earlier, today you have access to source code of all the
libraries you are using because Ruby is source based interpreter and
you can still debug problems because of accidental overrides or
modifying core classes by looking at source code, but what if Rubinius
or IronRuby becomes defacto and people started distributing compiled
bytecodes?

I propose a small change in the language and perhaps I know it won’t
see light of the day, but how about this?

class Array
def to_csv #> works if in final program no one is actually doing the
same
end
end

However, suppose you use another library and they have done the same,
that code won’t run and Ruby will throw up and that sorta makes
sense.However, if you are sure of what you are doing, you can go ahead
and write:

class Array
def! to_csv #=> similar to override keyword in other languages
end
end

Ditto, if you want to override methods defined in other classes, you
must use “def!” .

I know this is somewhat impractical because Ruby has grown into such a
beast, lots of standard library classes and gems will need small
modification ( but we are in midst of such modification anyways
courtesy of 1.9.x ).

My point is, I love open classes, but it shouldn’t hurt to have little
bit of safety precaution built into the language, does it?

On Feb 28, 2008, at 8:59 AM, Sam S. wrote:

Otherwise, like you said, you eventually
may not have the source for a lib, so you wouldn’t have a choice but
to abandon it or hack in something like:

require ‘faster_csv’
Array.send(:undefine_method, :to_csv)

Since we’ve been using FasterCSV’s extension to Array, I just wanted
to point out some small facts in it’s defense:

  • FasterCSV does support the alternative syntax:
    FCSV.generate_line(array)
  • Array#to_csv just wraps the above call, so there’s no danger of
    losing functionality if a collision occurs

In summary, Array#to_csv is provided just as a convenience to
developers. You are free to ignore it.

James Edward G. II

On Feb 28, 8:39 am, hemant [email protected] wrote:

http://weblog.techno-weenie.net/2007/12/19/adventures-in-rails-debugging
modifying core classes by looking at source code, but what if Rubinius

Ditto, if you want to override methods defined in other classes, you
must use “def!” .

I know this is somewhat impractical because Ruby has grown into such a
beast, lots of standard library classes and gems will need small
modification ( but we are in midst of such modification anyways
courtesy of 1.9.x ).

My point is, I love open classes, but it shouldn’t hurt to have little
bit of safety precaution built into the language, does it?

I’m with James on this, the wins from Ruby’s flexibility far out-weigh
the downsides.

On the other hand, I don’t think I’ve seen a suggestion quite like
this before. It’s pretty neat actually I think. Like a poor-man’s
selector-namespaces.

Now if we ever did get selector-namespaces, then I’d be completely
against this. But since it appears we’re not getting the feature,
this isn’t a half-bad substitute IMO.

Except for the “ruby throwing up” part. Collissions should be
warnings, not fatal errors. Otherwise, like you said, you eventually
may not have the source for a lib, so you wouldn’t have a choice but
to abandon it or hack in something like:

require ‘faster_csv’
Array.send(:undefine_method, :to_csv)

I’m not saying this def! idea is really needed… but I do thing it’s
pretty novel an idea, and I don’t see any downsides.

Hi,

On Thu, Feb 28, 2008 at 8:29 PM, Sam S. [email protected] wrote:

I’m with James on this, the wins from Ruby’s flexibility far out-weigh
the downsides.

I am with James on this as well. Open Classes is a feature and as I
said I love it.

On the other hand, I don’t think I’ve seen a suggestion quite like
this before. It’s pretty neat actually I think. Like a poor-man’s
selector-namespaces.

Now if we ever did get selector-namespaces, then I’d be completely
against this. But since it appears we’re not getting the feature,
this isn’t a half-bad substitute IMO.

I am with you here. If we can get selector-namespaces, we wouldn’t
need this. Although in case of overriding method
defined in parent class, ‘def!’ could still be useful.

pretty novel an idea, and I don’t see any downsides.


Let them talk of their oriental summer climes of everlasting
conservatories; give me the privilege of making my own summer with my
own coals.

http://gnufied.org

On Thu, Feb 28, 2008 at 9:39 AM, hemant [email protected] wrote:

My point is, I love open classes, but it shouldn’t hurt to have little
bit of safety precaution built into the language, does it?

In the mean time, a quick hack: Parked at Loopia

Example:

load ‘redefine.rb’
=> true

?> class Module

include Redefine

end
=> Module

?> class Monkey

def ook_ook
    puts "ook ook!"

load ‘redefine.rb’
=> true

?> class Module

include Redefine

end
=> Module

?> class Monkey

def ook_ook
    puts "ook ook!"
  end

end
=> nil

?> class Monkey

redefine_method(:ook_ook) { "please, may I have another banana?" }

end
Redefine::MethodRedefinitionError: Method ‘ook_ook’ redefined
from (irb):14

?> Monkey.new.ook_ook
ook ook!
=> nil

?> Redefine.allow_collisions= :warn
=> :warn

?> class Monkey

redefine_method(:ook_ook) { "please, may I have another banana?" }

end
Method ‘ook_ook’ redefined at (irb):22:in `irb_binding’
=> #Proc:0x00624224@:22(irb)

?> Monkey.new.ook_ook
=> “please, may I have another banana?”

?> Redefine.allow_collisions= true
=> true

?> class Monkey

redefine_method(:ook_ook) { "Look out, I'm in a poo-flinging mood" }

end
=> #Proc:0x004b0410@:30(irb)

?> Monkey.new.ook_ook
=> “Look out, I’m in a poo-flinging mood”

On Feb 28, 9:39 am, hemant [email protected] wrote:

As i wrote earlier, today you have access to source code of all the
def to_csv #> works if in final program no one is actually doing the same
end
My point is, I love open classes, but it shouldn’t hurt to have little
bit of safety precaution built into the language, does it?

I think there is deep misunderstanding about all this. The main issue
is really that Rails has added so many extensions to Ruby that
inexperienced Rails programmers follow suit and extend Ruby willy-
nilly. But that’s not Ruby’s problem. Ruby is an open “agile” language
–it lets you override almost any part of the system. Yes, that can be
“dangerous”, but it can also be extremely powerful. It’s up to the
programmer to consider their usecase and make the call. No amount of
preventative obstruction is going to make anything better, it will
only make life more difficult for those who use MP appropriately. I
personally think Ruby has too many meta-obstructions as it is. I
certainly don’t want more.

If we can come up with a real solution --eg. a good selector
namespaces design, then great. But short of that there is no point.
You can already do this:

$ cat temp.rb
class String
def to_s; “”; end
end

$ ruby -w temp.rb
temp.rb:2: warning: method redefined; discarding old to_s

That ought to be preventive care enough.

T.

On Feb 28, 9:59 am, Sam S. [email protected] wrote:

Now if we ever did get selector-namespaces, then I’d be completely
against this. But since it appears we’re not getting the feature,
this isn’t a half-bad substitute IMO.

Well, while I’m sitting here thinking about it, let’s try another
concept for selector namespaces:

class Array
def to_csv for FasterCSV
# …
end
end

class String
def to_a for FasterCSV
end

“”.to_a # will use Ruby’s
[].to_csv # NoMehtodError

space FasterCSV

“”.to_a # will use FasterCSV’s

Anything defined within FasterCVS will use the FasterCSV space by
default, in which case you’d have to say “space Ruby” to get access to
pure.

Space selections are reset per file.

T.

Topmost-level code could set up callbacks before the ‘require’ lines
for the needed libs. It would be the client’s responsibility to check
for changes and adapt to them.

SingletonListener.new(Array) { |singleton|
singleton # => Array

{
:reopened_begin => lambda {
# Encountered ‘class Array’ line … probably only useful for
thread sync
# …
},
:reopened_end => lambda {
# Encountered corresponding ‘end’ for the above ‘class Array’
# …
},
:method_added_begin => lambda { |method_name|
# Someone has begun adding a method, either with the line
# ‘def foo’ or define_method or otherwise
method_name # => String
# …
},
:method_added => lambda { |method|
# Forwarded from Module’s method_added
method.class # => UnboundMethod
},
:method_removed => lambda { |method|
# Forwarded from Module’s method_removed
# …
},
:const_added => lambda { |const_name, value|
# …
},
:const_removed => lambda { |const_name, value|
# …
},

  # ... other callbacks ...

}
}

For example I plan to define Array#foo, but I get a callback from the
library when it defines foo. After I’ve 'require’d everything I need,
but before I’ve required my libs, I could run a unit test on the
existing foo. If the results are identical to the test results of my
implementation, I’d perhaps leave it alone. If not, then at least I
know.

This could all be done without SingletonListener, but the idea is to
have a common idiom which people recognize and expect (if not
SingletonListener then something else).

–FC

On Feb 28, 10:15 am, James G. [email protected] wrote:

Since we’ve been using FasterCSV’s extension to Array, I just wanted
to point out some small facts in it’s defense:
James Edward G. II

James, no offense intended. In my book FasterCSV is just about the
most useful Ruby lib of all time. :slight_smile:

Trans wrote:

def to_csv for FasterCSV

space FasterCSV

“”.to_a # will use FasterCSV’s

Anything defined within FasterCVS will use the FasterCSV space by
default, in which case you’d have to say “space Ruby” to get access to
pure.

Space selections are reset per file.

Could even do this now, using semi-obscure method names instead of
namespaces:

class Array
def to_csv_for_FasterCSV
# …
end
end

class FasterCSV
def from obj # class name of obj isn’t embedded in method name!
obj.to_csv_for_FasterCSV
end
end

a = [1,2,3]
csv = FasterCSV.from(a)

We don’t have to switch on the type of a to call the right FasterCSV
method (or switch on the type of a to define a singleton #to_csv
method).

The chance of collision is greatly reduced by explicit naming.

The main disadvantage compared with Trans’s suggestion is that within
FasterCSV you have to use longer method names.

But the “public” API is kept clean because you use FasterCSV.from rather
than #to_csv_for_xxx.

On Thu, Feb 28, 2008 at 6:10 PM, Avdi G. [email protected] wrote:

In the mean time, a quick hack: Parked at Loopia

Example:

Avdi, sorry but it isn’t any solution for problem. You get warning or
exception and method won’t be overriden. Imagine that you want use 2
libraries that collide and you get sach a error. Is it usefull?
Another problem is that there are at least two cases why you are
opening existing class and adding features to them:
#1 You open class to just add new method and your library depend on it
for example
class String
def underscore
#…
end
end

When other library do the same there is problem because first library
use diffretent method than defined by itself.

#2 You open class to knowingly override existing method to
change/enhance it
class ActiveRecord::Base
def find(*args)
#…
end
end

The same problem here: if other library/plugin/whatever do the same
after our change then we have problem.

James, Sometime ago Rick O. wrote this:

http://weblog.techno-weenie.net/2007/12/19/adventures-in-rails-debugging

Great story. My opinion is rails and many other libraries use too much
MP. This story shows it. Opening String class just to add stupid
“underscore” method? So evil.


Rados³aw Bu³at

http://radarek.jogger.pl - mój blog

Now if we ever did get selector-namespaces, then I’d be completely
against this. But since it appears we’re not getting the feature,
this isn’t a half-bad substitute IMO.

I made a suggestion for this a few hours ago. Looks like it got lost
in cyberspace :frowning: Oh well, I’ll be extra brief this time, but
reiterate the idea:

class Array
def to_csv for FasterCSV
#…
end
end

[].to_csv #=> NoMethodError

space FasterCSV

[].to_csv #=> useses FasterCSV’s version

space Ruby

[].to_csv #=> NoMethodError

Anything defined in FasterCSV would automatically use FasterCSV space
(use ‘space Ruby’ to get pure space).

T.

On Thu, Feb 28, 2008 at 9:02 PM, Trans [email protected] wrote:

  #...

[].to_csv #=> NoMethodError

Anything defined in FasterCSV would automatically use FasterCSV space
(use ‘space Ruby’ to get pure space).

I like this one. I see two issues that still needs to be resolved:

  1. How to get at several spaces.
  2. What’s the speed penalty involved?

Eivind.

Responding to Trans:

[].to_csv #=> useses FasterCSV’s version

space Ruby

[].to_csv #=> NoMethodError

Looks somewhat similar to the “context-oriented programming” approach.

http://www.swa.hpi.uni-potsdam.de/cop/

Best regards,
Patrick

Hi Trans,

On Thu, Feb 28, 2008 at 10:57 PM, Trans [email protected] wrote:

certainly don’t want more.
Rails has increased Ruby’s mind share significantly and perhaps first
time Ruby is being used to built applications that are really complex
and large. For example, I do significant work in Ruby without Rails
and my Rails project size is currently 71498 lines ( including
plugins that I am using, but not the framework and not counting
Javascript, rhtml,css,xml,yaml ).

Too often, I have seen people blaming everything to Rails, but I do
not think its true in this case.
In the first link that I posted, whose fault it is? I have 103 gems
installed on my machine, and not counting
Rails libraries and facet , I still have around 5 or 6 of them, which
are modifying core classes one way or the other.

Trans, often on #ruby-lang I have heard from experienced rubyists why
they avoid facet. I do not think, its a problem of rails.
Ruby has grown and is being used by people with varying skills. I do
not think, features that help people in avoiding these problems is
bad.

As a last note, I will leave you with this:

http://blog.brightredglow.com/2008/1/17/evil-can-be-dangerous

So, no its not specific to Rails. Its not a problem either, but we can
do better.

$ ruby -w temp.rb
temp.rb:2: warning: method redefined; discarding old to_s

That ought to be preventive care enough.

T.


Let them talk of their oriental summer climes of everlasting
conservatories; give me the privilege of making my own summer with my
own coals.

http://gnufied.org

On Feb 29, 2008, at 11:29 PM, James B. wrote:

Too annoying.

Well, Rails internals are truly gruesome sometimes. I just had a long
session trying to change some behaviour in the routing system. There
are multiple real wtfs in it… well, back to topic.

It’s the static typing permathread in disguise.

Hehe, it may be… i don’t think we that another language construct
helps. As some have illustrated, all those problems can be solved with
discipline on both sides (authors and users). If i wanted a language
construct for everything, i’ll head back to Java || C++.

The only solution that would be an addition to the language would be
real selector namespaces.

Greetings
Skade

hemant wrote:

James, Sometime ago Rick O. wrote this:

http://weblog.techno-weenie.net/2007/12/19/adventures-in-rails-debugging

Does ring a bell, doesn’t it?

No. Why should it?

I try to avoid Rails.

Too annoying.


My point is, I love open classes, but it shouldn’t hurt to have little
bit of safety precaution built into the language, does it?

Ah HA! I knew it!

It’s the static typing permathread in disguise.


James B.

“Tear it up and start again.”

  • Anonymous