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 Levitt |
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

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

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 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 is not enough to be compassionate. you must act.
h.h. the 14th dalai lama

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 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://www.jay.fm | - Kristoffer

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

···

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.

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

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.

Hi Jay,

Do other languages do anything like that?

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

Cheers,
Bob

···

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

--
Jay Levitt |
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 Hutchison -- 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/

[...]

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

···

On Tue, Oct 09, 2007 at 01:10:07PM +0900, Jay Levitt wrote:

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.

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

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 Tue, 09 Oct 2007 00:06:18 -0400, 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.

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?

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

[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

···

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

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 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?

--
Jay Levitt |
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

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.

···

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.

--
Jay Levitt |
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

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

dean

···

On 10/9/07, Clifford Heath <no@spam.please.net> 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*. ...

--
Dean Wampler
http://www.objectmentor.com
http://www.aspectprogramming.com
http://aquarium.rubyforge.org
http://www.contract4j.org

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.

···

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.

--
Jay Levitt |
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

Hello,

> 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 Wed, 2007-10-10 at 05:05 +0900, Jay Levitt wrote:

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

--
Ubiquitous Business Technology, Inc http://www.ubit.com/
Michael Reinsch Tel: +81-3-5804-0104

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.