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.
on 2007-06-06 05:04
on 2007-06-06 09:55
Sunny Hirai wrote: > 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.