Help repost to Ruby Dev -- 2 improvements to Ruby Magic

S

Sunny Hirai

This is a proposed solution to simplify magic in Ruby.

I'd appreciate it if somebody who has post access to 'Ruby-core' or
'Ruby-dev' could post this message there. Thank you in advance. If you
get to read this Matz, thank you for bringing about such an excellent
language.

-----

I'm building a framework that has similarities to Ruby on Rails and Merb
but targets the creation of website building software.

In writing this software, one of the problems when reading other
people's code to get ideas is that it is difficult to find the magic
methods. Of course, there are several types of magic but I'd like to
propose solutions to help eliminate the confusion that two common types
of magic cause.

1. Precede methods that are meant to be automagically called by 'on_'

Here are a few examples for the Ruby language:

* on_method_missing
* on_initialize

I consider them magic because they do something automatically and there
is no direct call to either the 'method_missing' or 'initialize' method.

And for adding methods that are automagically called to a class:

* on_process
* on_before_read
* on_after_read
* on_before_create
* on_after_create

When starting Ruby, it was difficult to know what the magic methods were
and typically they were the last things to be mentioned in documentation
(with the exception of initialize). They are second nature now but this
naming convention makes it obvious that a method is a magic call making
it simpler to learn the language for beginners. You just need to teach
that 'on_' means this method is called automagically in some way and
from there you look up what the 'on_whatever' call does.

Also, consider the readability in the context of a lot of other methods.

old way:
* initialize
* new
* create
* edit
* post
* validate
* method_missing

new way:
* on_initialize
* new
* create
* edit
* post
* on_validate
* on_method_missing

In the second of the two lists above, it is obvious which methods get
executed automatically. For example, you may have known 'initialize' and
'method_missing' were, but there was probably no indication that
'validate' was called automatically. This is great for experienced users
trying to quickly understand a class, but it is especially good for new
users because they know that on_method_missing and on_initialize are
magically called methods, and that on_validate is special in some way.

One problem I had with reading through other source code was that it was
difficult for me to tell where the entry points (magic methods) for the
classes were without reading the RDoc. Locating the magic methods is
time consuming, because you have to go through every method in the
class. For example, Mongrel needs you to instantiate a handler class and
then it calls 'process' when the handler needs to be executing. But
reading the method names doesn't help you without first knowing that the
method 'process' is the entry point. If the Ruby standard was to start
with 'on_' and the method was named 'on_process', you could find the
entry point either almost immediately, or at least reduce your search to
a small handful of magic 'on_' methods.

It was also difficult to find where magic methods were called from. This
would be obvious if it was named on_before_read. This would allow for
simple searching for the string 'on_'. I know its not foolproof
searching, (e.g. may match 'json_read' though you can get around this
with a regex as well) but it makes our job a little easier.

2. Methods that are configuration should be preceded by 'has_'

I love Rails configuration but it is hard to find what framework code is
configuration without first learning the entirety of the framework. The
rails convention (to use no brackets for configuration) helps when
reading code but only when you read/write code that uses the framework.
It doesn't help when trying to read/write the framework itself.

Consider these methods in a class:

* attr_reader
* has_many
* belongs_to
* initialize
* helper
* prepare_stuff
* before_create
* after_read

This is typically how classes read in Ruby.

Now what about we rewrite this with our conventions

* has_attr_reader (or has_reader)
* has_children
* has_parent
* on_initialize
* helper
* prepare_stuff
* on_before_create
* on_after_read

It is clear now which methods are automagically called, which ones are
configuration and which ones are POMs (Plain Old Methods). In fact, this
would probably help us organize our code at the subconscious level too.
Because I want to reorder my methods now to look nicer, though there is
no requirement that I do (I know in some cases it is better to have the
magic calls closer to related calls):

* has_attr_reader
* has_children
* has_parent
* on_initialize
* on_before_create
* on_after_read
* helper
* prepare_stuff

One thing you may be thinking about with the 'has_' convention is this:

Will 'has_' work for every type of configuration? The answer is, I think
so. I went through a book on Rails (I think I own every Ruby and Rails
book published including some online ones) to see if every instance of
configuration could be rewritten with a 'has_'. I considered different
prefixes but found that 'has_' could be used in every case that I came
across. In some cases, you had to be creative, but in no case was the
name bad. In fact, I personally found that many of the names were
better.

Another benefit of standardizing on 'has_' is that it makes all
configuration method names consistent. For example, 'attr_reader' is a
noun, 'has_many' is, well, some other part of the English language.
Having consistency helps us better understand what configuration does
which is it describes some aspect of a class. For this use, 'has_' is a
pretty good prefix.

Finally, you may be concerned about my 'opinion' making its way into the
language.

Do the 'on_' and 'has_' changes really need to be made in the Ruby
language itself? Isn't Mr. Hirai just trying to force me to program the
way he programs? Why doesn't he just use it for himself? Well the answer
is that I think it is important to have it in the Ruby language just
like the convention for '?' and '!' on method name endings is used in
the Ruby language. Nothing stops anybody from using the punctuation in
other ways, but the convention in the base language has helped to make
it work properly with all code. For example, if '!' was used for
exciting methods, the value of the '!' would non-existent. It would just
be another character in variable names.

I know this sounds funny but try imagining that all automagic calls
start with 'on_' and 'has_'. Think of how much easier it would be to
read code that involved callbacks and meta programming. If you are
having trouble picturing the difference semantics make, think of how
much more difficult life would be if Ruby did NOT have '!' and '?' for
method names. In fact, that simple punctuation has solved many naming
conflicts.

Well, that's it for now, but I'd be happy to discuss this more. This is
a convention that I've already adapted for use in our web framework and
it works. I'm also considering writing a new database abstraction
library like ActiveRecord (but multi-threaded, connection pooling,
multi-datasource, split-datasource for read/write, etc.) and would use
it there..

Again, if somebody has post access (or know somebody that does), I'd
appreciate getting this in front of Matz and other contributors to the
Ruby language.

Sunny Hirai
CEO, MeZine Inc.
 
A

Alex Young

Sunny said:
This is a proposed solution to simplify magic in Ruby.

I'd appreciate it if somebody who has post access to 'Ruby-core' or
'Ruby-dev' could post this message there. Thank you in advance. If you
get to read this Matz, thank you for bringing about such an excellent
language.
<snip on_ and has_ proposal>

I quite like this. I often feel that there's not quite enough
consistency in method naming. It's more a problem in the stdlib than in
core, though. The great thing about this specific proposal is that it's
completely (I think) implementable with aliases, so it needn't break
anything.
 

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,969
Messages
2,570,161
Members
46,710
Latest member
bernietqt

Latest Threads

Top