[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

The Open-Closed-from-a-certain-angle Principle

Jay Levitt

10/9/2007 4:06:00 AM

Let me start off by saying that I'm SURE this is either a bad idea,
impossible to implement, or both. I just can't enumerate the reasons why,
and I thought this would be a good group to shoot it down.

Since it's so easy to add new functionality to Ruby core classes (which are
open for extension), many libraries do. Rails adds all sorts of things in
Active Support, and other frameworks and libs do similar things. Gems does
with Time::today, but is about not to, so that it doesn't step on anyone
else's Time machines.

Yet adding, say, String#to_leetspeak is a much cleaner alternative than
defining a global to_leetspeak(String) method. The key is to stop the
leetspeak from leaking into other modules.

What if class definitions were viewed through a magic prism, where only
those classes looking from the right perspective saw the new extensions?
Mind you, I have no idea how to partition the codespace in any sane manner
- even from a design spec point-of-view. Should ActiveRecord see Og's
extensions? Probably not; but ActionView and ActionPack might want to
share. And what happens if Og passes a Hash to ActiveRecord that happens
to include an Og-provided Time#today in it?

I dunno. On the surface it seems that there must be some nicer way to add
better locality of reference to core extensions, but I can't imagine how it
would be implemented, how it should work, or if it would even be a good
idea. Just some good old Sunday night musings.

Do other languages do anything like that?

--
Jay Levitt |
Boston, MA | My character doesn't like it when they
Faster: jay at jay dot fm | cry or shout or hit.
http://... | - Kristoffer
15 Answers

Joel VanderWerf

10/9/2007 4:38:00 AM

0

Jay Levitt wrote:
...
> What if class definitions were viewed through a magic prism, where only
> those classes looking from the right perspective saw the new extensions?
> Mind you, I have no idea how to partition the codespace in any sane manner
> - even from a design spec point-of-view. Should ActiveRecord see Og's
> extensions? Probably not; but ActionView and ActionPack might want to
> share. And what happens if Og passes a Hash to ActiveRecord that happens
> to include an Og-provided Time#today in it?

Maybe selector namespaces? There's been some discussion here and hints
of having them in ruby 2.0. Search the archives if you're interested...

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

ara.t.howard

10/9/2007 4:51:00 AM

0


On Oct 8, 2007, at 10:10 PM, Jay Levitt wrote:

> What if class definitions were viewed through a magic prism, where
> only
> those classes looking from the right perspective saw the new
> extensions?

it's not too hard to imagine something like that:

cfp:~ > cat a.rb
module Namespace
class File < ::File
def self.xopen *a, &b
open *a, &b
end
end

def self.eval(&b) module_eval(&b) end
end

module Namespace
File.xopen __FILE__ do |fd|
puts fd.gets.scan(%r/\w+/).last
end
end


cfp:~ > ruby a.rb
Namespace


cheers.

a @ http://codeforp...
--
it is not enough to be compassionate. you must act.
h.h. the 14th dalai lama




Pat Maddox

10/9/2007 5:26:00 AM

0

On 10/8/07, Jay Levitt <jay+news@jay.fm> wrote:
> Let me start off by saying that I'm SURE this is either a bad idea,
> impossible to implement, or both. I just can't enumerate the reasons why,
> and I thought this would be a good group to shoot it down.
>
> Since it's so easy to add new functionality to Ruby core classes (which are
> open for extension), many libraries do. Rails adds all sorts of things in
> Active Support, and other frameworks and libs do similar things. Gems does
> with Time::today, but is about not to, so that it doesn't step on anyone
> else's Time machines.
>
> Yet adding, say, String#to_leetspeak is a much cleaner alternative than
> defining a global to_leetspeak(String) method. The key is to stop the
> leetspeak from leaking into other modules.
>
> What if class definitions were viewed through a magic prism, where only
> those classes looking from the right perspective saw the new extensions?
> Mind you, I have no idea how to partition the codespace in any sane manner
> - even from a design spec point-of-view. Should ActiveRecord see Og's
> extensions? Probably not; but ActionView and ActionPack might want to
> share. And what happens if Og passes a Hash to ActiveRecord that happens
> to include an Og-provided Time#today in it?
>
> I dunno. On the surface it seems that there must be some nicer way to add
> better locality of reference to core extensions, but I can't imagine how it
> would be implemented, how it should work, or if it would even be a good
> idea. Just some good old Sunday night musings.
>
> Do other languages do anything like that?
>
> --
> Jay Levitt |
> Boston, MA | My character doesn't like it when they
> Faster: jay at jay dot fm | cry or shout or hit.
> http://... | - Kristoffer
>
>

I don't want to get too caught up in your example, but I think that's
one spot where a new class is better than defining a new method on
String. For example, what happens if you do "my cool
sentence".to_leetspeak.to_leetspeak? Does it just become some super
garbled stuff?

The classic example from Java-land is escaped and unescaped strings in
a webapp. When you get some input from the user, you create an
escaped string at the top layer. new EscapedString(userInput). Then
you pass that around, and in each layer you can call new
EscapedString(the_string), which escapes it if it's a basic string and
just returns itself if it's already escaped. That way you assume that
each string is unsafe, but you don't get bit by funky implementation
details.

Anyway, I think it would be cool if things were sandboxed. You could
register them globally in your app

String.use_extensions :leetspeak

so now every string in the app has #leetspeak on it. Or you could
sandbox them in a block

String.use_extensions :leetspeak do
"I am cool".to_leetspeak # => "I 4m k3w1"
end

"I am not".to_leetspeak # => NoMethodError

Pat

Alex Gutteridge

10/9/2007 5:51:00 AM

0

On 9 Oct 2007, at 14:26, Pat Maddox wrote:
> Anyway, I think it would be cool if things were sandboxed. You could
> register them globally in your app
>
> String.use_extensions :leetspeak
>
> so now every string in the app has #leetspeak on it. Or you could
> sandbox them in a block
>
> String.use_extensions :leetspeak do
> "I am cool".to_leetspeak # => "I 4m k3w1"
> end
>
> "I am not".to_leetspeak # => NoMethodError
>
> Pat

[alexg@powerbook]/Users/alexg/Desktop(18): cat temp_extend.rb
class Class
def uninclude(mod)
mod.instance_methods.each do |meth|
undef_method(meth)
end
end
def use_module(mod,&blk)
include mod
if block_given?
blk.call
uninclude(mod)
end
end
end

module Foo
def to_foo
'foo'
end
end

module Bar
def to_bar
'bar'
end
end

String.use_module(Foo)
p "bar".to_foo

String.use_module(Bar) do
p "foo".to_bar
end
p "foo".to_bar
[alexg@powerbook]/Users/alexg/Desktop(19): ruby temp_extend.rb
"foo"
"bar"
temp_extend.rb:34: undefined method `to_bar' for "foo":String
(NoMethodError)

Alex Gutteridge

Bioinformatics Center
Kyoto University



Eric Hodel

10/9/2007 6:22:00 AM

0

On Oct 8, 2007, at 21:10 , Jay Levitt wrote:
> Let me start off by saying that I'm SURE this is either a bad idea,
> impossible to implement, or both. I just can't enumerate the
> reasons why, and I thought this would be a good group to shoot it
> down.
>
> Since it's so easy to add new functionality to Ruby core classes
> (which are open for extension), many libraries do. Rails adds all
> sorts of things in Active Support, and other frameworks and libs do
> similar things. Gems does with Time::today, but is about not to,
> so that it doesn't step on anyone else's Time machines.

Just to be clear, RubyGems is about to remove Time::today if you take
about to to mean 6+ months into the future.

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



Clifford Heath

10/9/2007 7:33:00 AM

0

Jay Levitt wrote:
> What if class definitions were viewed through a magic prism, where only
> those classes looking from the right perspective saw the new extensions?
....
> Do other languages do anything like that?

I put a lot of thought into this over the last ten years because I spent
a long time thinking about Aspect Oriented *Design*. What you're suggesting
is what the term "aspect-oriented programming" *ought* to attach to. The
idea of aspects is that everything has many facets, and only some of those
facets are visible at once, only those that belong to aspects that are in
view. In this way each aspect injects additional "features" into one or
more classes.... but they shouldn't be allowed to change behaviour (break
expectations, slightly weaker) of any users unaware of the aspect.

To do this without breaking encapsulation, each facet may only use the
public interface of the object, and in fact shouldn't affect the object's
state... pretty restrictive. When you consider deeply what's required to
do it without obscure side-effects, it must be too restricted to be very
useful. I don't know of any programming languages that really do it.

Then there's a whole lot of interesting things to do with delayed facet
realization... sorta like instantiation, but to add a facet to an object
created by a user having no knowledge of the aspect in which it's now
being used.

I don't know, it might be possible to construct a useful language that does
it, but I don't think Ruby is the right starting point, and I couldn't
work out exactly how it'd look.

AOD works very well for me though... It helps to keep people's mind on the
discussions when they know their off-topic contributions can be filed to
be discussed later (under another aspect), instead of just shrugged off.

Clifford Heath.

Jay Levitt

10/9/2007 9:14:00 AM

0

On Tue, 9 Oct 2007 14:26:19 +0900, Pat Maddox wrote:

> I don't want to get too caught up in your example, but I think that's
> one spot where a new class is better than defining a new method on
> String. For example, what happens if you do "my cool
> sentence".to_leetspeak.to_leetspeak? Does it just become some super
> garbled stuff?

An entire Myspace page!

No, you're right, bad example, because the output of #to_leetspeak is a
String that can't be differentiated the way EscapedString can.

You knew what I meant though, so thanks :)

--
Jay Levitt |
Boston, MA | My character doesn't like it when they
Faster: jay at jay dot fm | cry or shout or hit.
http://... | - Kristoffer

Jay Levitt

10/9/2007 9:15:00 AM

0

On Tue, 9 Oct 2007 15:22:10 +0900, Eric Hodel wrote:

> Just to be clear, RubyGems is about to remove Time::today if you take
> about to to mean 6+ months into the future.

Well, I didn't know that, since I don't know what today is anymore... or I,
uh, wouldn't have known later when it... oh, forget it.

--
Jay Levitt |
Boston, MA | My character doesn't like it when they
Faster: jay at jay dot fm | cry or shout or hit.
http://... | - Kristoffer

Bob Hutchison

10/9/2007 11:42:00 AM

0

Hi Jay,

On 9-Oct-07, at 12:10 AM, Jay Levitt wrote:
>
> Do other languages do anything like that?
>

You might want to check out <http://common-lisp.net/proje...
contextl.html>, the overview paper is pretty good.

Cheers,
Bob

> --
> Jay Levitt |
> Boston, MA | My character doesn't like it when they
> Faster: jay at jay dot fm | cry or shout or hit.
> http://... | - Kristoffer
>

----
Bob Hutchison -- tumblelog at http://
www.recursive.ca/so/
Recursive Design Inc. -- weblog at http://www.rec...
hutch
http://www.rec... -- works on http://www.racon...
cms-for-static-content/home/




Gregory Seidman

10/9/2007 2:30:00 PM

0

On Tue, Oct 09, 2007 at 01:10:07PM +0900, Jay Levitt wrote:
[...]
> What if class definitions were viewed through a magic prism, where only
> those classes looking from the right perspective saw the new extensions?
> Mind you, I have no idea how to partition the codespace in any sane manner
> - even from a design spec point-of-view. Should ActiveRecord see Og's
> extensions? Probably not; but ActionView and ActionPack might want to
> share. And what happens if Og passes a Hash to ActiveRecord that happens
> to include an Og-provided Time#today in it?
>
> I dunno. On the surface it seems that there must be some nicer way to add
> better locality of reference to core extensions, but I can't imagine how it
> would be implemented, how it should work, or if it would even be a good
> idea. Just some good old Sunday night musings.
>
> Do other languages do anything like that?

I know of no language that does anything like it. That said, there are good
reasons to want something like it. Actually, I have often wanted a
construct like this:

class SomeClass

module ExtraStuff
def my_extra_method
#...
end
end

def some_method(arg)
arg.let_extended(ExtraStuff) do |ext_arg|
ext_arg.my_extra_method
#...
end
end

end

If it isn't obvious, I want the equivalent of arg.extend(ExtraStuff) but
only within the scope of the block. Whatever my ExtraStuff module does, I
only want it mixed into an object for a brief scope. The simple solution
is:

#...
def some_method(arg)
ext_arg = arg.dup
ext_arg.extend(ExtraStuff)
ext_arg.my_extra_method
#...
end
#...

But that doesn't read quite as cleanly, and I would prefer a core language
construct that could do it efficiently (i.e. without an object copy).
Furthermore, the semantics are different in that if my_extra_method changes
the state of the object, the state of the object passed into the method
will actually changed when using the hypothetical core language construct,
but not when using an extended copy of that object.

There's been discussion before about unincluding modules, but it's always
been considered too complicated to implement (I think). For this construct,
however, it should be as simple as copying the object's eigenclass,
including the module (or modules, since the let_extended method should
really take an arbitrary number of modules) in the duplicate eigenclass,
and setting the object's eigenclass pointer to the duplicate for the scope
of the block. I speak of this with only a vague knowledge of how MRI deals
with eigenclasses, much less how any other implementation (e.g. JRuby or
Rubinius) does, so it may be messier than that.

Does anyone find this interesting enough to push for an RCR? I've never
done one, but if I get some positive feedback then I'll look into it.

> Jay Levitt |
--Greg