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

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 L. 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…

On Oct 8, 2007, at 10:10 PM, Jay L. 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://codeforpeople.com/

On 10/8/07, Jay L. [email protected] wrote:

Yet adding, say, String#to_leetspeak is a much cleaner alternative than

Faster: jay at jay dot fm | cry or shout or hit.
http://www.jay.fm | - 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

On 9 Oct 2007, at 14:26, Pat M. wrote:

end

“I am not”.to_leetspeak # => NoMethodError

Pat

[[email protected]]/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
[[email protected]]/Users/alexg/Desktop(19): ruby temp_extend.rb
“foo”
“bar”
temp_extend.rb:34: undefined method `to_bar’ for “foo”:String
(NoMethodError)

Alex G.

Bioinformatics Center
Kyoto University

Jay L. 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 H…

On Oct 8, 2007, at 21:10 , Jay L. 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.

On Tue, 9 Oct 2007 14:26:19 +0900, Pat M. 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 :slight_smile:

On Tue, 9 Oct 2007 15:22:10 +0900, Eric H. 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.

Hi Jay,

On 9-Oct-07, at 12:10 AM, Jay L. wrote:

Do other languages do anything like that?

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

Cheers,
Bob


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


Bob H. – tumblelog at http://
www.recursive.ca/so/
Recursive Design Inc. – weblog at http://www.recursive.ca/
hutch
http://www.recursive.ca/ – works on http://www.raconteur.info/
cms-for-static-content/home/

On Tue, Oct 09, 2007 at 01:10:07PM +0900, Jay L. wrote:
[…]

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 L. |
–Greg

On 10/9/07, Clifford H. [email protected] wrote:

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. …

Me too:
http://aosd.net/2007/program/industry/I6-AspectDesignPrinciples.pdf

dean

Jay L. 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.

I’ve been thinking about some simpler, yet similar problem ever since I
started to learn ruby a few months ago.

Having modules to partition name space is great - but since any feature
can extend any pre-existing class/module with its own methods, those are
in no way proected from name clashes within a given module/class.

Has this issue been discussed already to any extent?

mortee

Hello,

On Wed, 2007-10-10 at 05:05 +0900, Jay L. wrote:

On Wed, 10 Oct 2007 01:53:43 +0900, mortee wrote:

Having modules to partition name space is great - but since any feature
can extend any pre-existing class/module with its own methods, those are
in no way proected from name clashes within a given module/class.

Yeah, that’s really the core of it - preventing namespace collisions, so
that gems’s Time::today doesn’t conflict with, I dunno, facets’s.

I also did some thinking about this matter (though not specifically for
ruby) from the angle of software evolution and outlined some ideas in a
paper for RAM-SE05 (http://mr.uue.org/me/pub/disentangledparts.pdf).
Though this paper describes a different approach to tackle the problem,
it made me think more about method dispatching and I now think that this
could probably be done by extending the dispatching mechanism. Why in
the dispatching mechanism?

Well, dispatching usually chooses a method based on the object’s class.
Or on a more abstract level we could call the dispatching criteria the
“object’s context” (in lack of a better name), as it is bound to the
object. So we can say: the usual dispatching as we know it is done on
the object’s context.

The idea now would be to extend this and to also allow dispatching on
the other contexts, such as the caller’s context. What is that “caller’s
context”? Well, this needs to be defined per implementation probably,
but as the name suggests, this is something bound to the caller of a
method.

Don’t think something like that is needed? Well, actually, ruby (and
most other OO languages) already take a very simple caller context into
account when a method is called, defined by “public”, “protected” and
“private”. C++ supports friends, which also defines a caller context.

But redefinition of methods is usually not allowed in existing
implementations for different contexts other than the object’s context.

One big challenge is IMHO coming up with easy and natural ways to define
those caller contexts (and other contexts) within a language. But as
this email is already quite long, I’ll stop here in the hope I could
seed some ideas. I already got some interesting new pointers through
this thread. Thanks to everybody participating!

On Tue, 09 Oct 2007 00:06:18 -0400, Jay L. wrote:

Yet adding, say, String#to_leetspeak is a much cleaner alternative than

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?

Groovy does something like this with use(Category){ code… }. The only
thing is that the added methods are visible to everything that the
included code calls, whether you wrote it or not. So it’s still not
quite
what you’re asking for.

–Ken

On Wed, 10 Oct 2007 01:53:43 +0900, mortee wrote:

Having modules to partition name space is great - but since any feature
can extend any pre-existing class/module with its own methods, those are
in no way proected from name clashes within a given module/class.

Yeah, that’s really the core of it - preventing namespace collisions, so
that gems’s Time::today doesn’t conflict with, I dunno, facets’s.

Michael Reinsch wrote:

The idea now would be to extend this and to also allow dispatching on
the other contexts, such as the caller’s context. What is that “caller’s
context”? Well, this needs to be defined per implementation probably,
but as the name suggests, this is something bound to the caller of a
method.

I think the name collision problem might best be solved on a file-based
approach. It should work something like how the method namespace
partitioned by modules works on a class-based approach.

I mean, any source file should be able to state a, let’s say, “layer” (I
don’t have a better term for now), which is simiar to a module. Any
methods this file adds to existing classes/modules would be associated
to that layer. (*)

Now, any file which makes use of the extra methods added by the file
mentioned above should explicitely state that it uses the named layer.
This property wouldn’t be inherited by other files when they require
this one.

This way, any library/application could define its own private layer of
methods, which all of the source files of the given package could state
to use - thus defining and using its own utility methods (added to core
classes or ones of other libraries). Yet this wouldn’t conflict with
other used packages’ own private utility methods (because the layer
usage wouldn’t be inherited from file to file).

Also, if an application wants to use those utility methods defined by
some library, it can do so, without disturbing other used libraries.

Does this make sense? Could it be implemented in a reasonable way?

mortee

(*) I propose using named layers instead of filenames themselves so that
multiple files could state the same layer - and this would also mean
they also use the layer they state. This way, every file of a given
package could state and use a single shared layer, in one step. This may
be simplified even further if the layer can be specified by the package
itself the file in question belongs to: then one would have to
explicitely use only other packages’ layers, the current package’s layer
would be included automatically.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs