improvements on mixins

J

Joseph Lenton

I'm currently building a Ruby-like language, heavily influenced by Ruby.
One things I'm planning to add soon is modules, mainly for mixins (and
this will only be how it'll be used at first).

But as it's Ruby-like not Ruby I'm also trying to think of improvements
I can make, things I can add which are better.

What I'm currently thinking of is adding a 'before' and 'after' keyword
for methods in modules, like:

module Foo
after bar()
// do something
end
end

If the module is included to a class that contains the method 'bar',
then the modules 'bar' method is called after the classes bar method.
I'm pretty
certain it's possible to build stuff like this in Ruby, but I'm thinking
of baking this into my language to make it easier to do more aspect-like
programming.

My language is for games development, and so one good example of this is
that you could build the different parts of the AI as separate modules
which each run after a generic 'update' method stub. Such as modules for
DamagePlayer, MoveToPlayer, MoveRandomly, and so on. Game classes can
then include all the different modules to that make them.

What I'm after is some feedback on this idea. An alternative would be to
keep modules as modules and build this as a separate aspect components
that cut into those classes. Do people think my suggestion would do this
better or worse then that?

If you were also trying to build a better module system then Ruby's
(which I already think is better then those in most languages) what
would you want to be able to do?

Another idea I was thinking of moving towards would be if you could
compose whole objects solely from mixing modules together. Like an
asteroid could be a Drawable( asteroid_image ) + MoveRandomly +
DamagePlayer.

What are peoples thoughts?
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

If the module is included to a class that contains the method 'bar',
then the modules 'bar' method is called after the classes bar method.
I'm pretty
certain it's possible to build stuff like this in Ruby, but I'm thinking
of baking this into my language to make it easier to do more aspect-like
programming.
If you do that, it would be nice if you could register any number of
callbacks with it, and they will all be run, so that you don't have to put
all your after behaviour in one place, but can instead have lots of code
receive notification of this method's completion. I am curious what this
method will receive, your example looked like it took parameters, how do you
intend to pass parameters to it?

If you were also trying to build a better module system then Ruby's
(which I already think is better then those in most languages) what
would you want to be able to do?
When I include a module, I would want to be able to pass it parameters, so
the module could customize its methods for the class more intelligently. For
example, if you want to use Ruby's Enumerable module, you must define #each.
But what if you could name your iterator whatever you wanted? Well, to make
that happen you have to jump through some counter-intutive hoops, like they
do with Rails plugins. Okay, naming it something other than each isn't very
useful, but think about things like Paperclip, where you can name your
attachment whatever you want, and the methods it creates will be customized
accordingly.

Another idea I was thinking of moving towards would be if you could
compose whole objects solely from mixing modules together. Like an
asteroid could be a Drawable( asteroid_image ) + MoveRandomly +
DamagePlayer.
I like that idea, but don't really see how it is an advantage over just
having a class. Why not just mix those modules into the Asteroid class, then
when you create a new asteroid, it has all of that functionality without
having to mix those modules into every single asteroid's singleton class (or
however you intend to implement it). Also, you can do this right now, in
Ruby:

module Drawable
def draw
end
end

module MoveRandomly
def move
end
end

module DamagePlayer
def damage
end
end

def asteroid
Object.new.instance_eval do
extend Drawable # here it would be nice to be able to say :image =>
"images/asteroid.png"
extend MoveRandomly
extend DamagePlayer
self
end
end

asteroid.methods.grep(/^(draw|move|damage)$/) # => [:damage, :move, :draw]
(class << asteroid ; self ; end).ancestors # => [DamagePlayer, MoveRandomly,
Drawable, Object, Kernel, BasicObject]





Anyway, good luck with it, but I would consider what changes you want to
make, and whether they really warrant creating an entirely new Ruby-like
language, or if the similarities are strong enough that just using Ruby
itself is satisfactory, and to implement the unique aspects, you could just
create a framework on top of it. For example, everything you said here seems
doable in Ruby, Rails and many test suites have before and after methods /
callbacks, Rails has parameter passing to modules, as I showed above, you
can already create objects by mixing modules into their singleton classes.

As a last thought, you might look into doing what Mirah did, which is modify
Ruby's parser and just map it to their own back end. This is how they got
Java with Ruby syntax. You could save yourself a lot of work by doing
something like that.
 
J

Joseph Lenton

If you do that, it would be nice if you could register any number of
callbacks with it, and they will all be run, so that you don't have to
put
all your after behaviour in one place, but can instead have lots of code
receive notification of this method's completion.

This is how I want it to be too. So calling 'update' on a game object
might end up calling 10 different update functions that are all set to
be called around the original update method.
I am curious what this
method will receive, your example looked like it took parameters, how do
you
intend to pass parameters to it?

The parameters passed in are those passed to the method it's hanging
off. So if you call 'obj.foo( 5 )' then that 5 is also passed into the
'before' and 'after' methods in the imported module, before and after
foo is called on the class. One difference to Ruby is that my language
supports method overloading, so foo(a) and foo(a, b) can both exist in a
class and are entirely different methods.
When I include a module, I would want to be able to pass it parameters,
so
the module could customize its methods for the class more intelligently.
For
example, if you want to use Ruby's Enumerable module, you must define
#each.
But what if you could name your iterator whatever you wanted? Well, to
make
that happen you have to jump through some counter-intutive hoops, like
they
do with Rails plugins. Okay, naming it something other than each isn't
very
useful, but think about things like Paperclip, where you can name your
attachment whatever you want, and the methods it creates will be
customized
accordingly.

I think I fail to quite see what your after. But I do like the idea of
altering method signatures because it could make it easier to get
modules from different sources to match up. Like if one module appends
functionality on the 'update' method whilst another appends onto 'act'.
They don't match up and so you'd want to change say the 'act' to
'update'.

Building in the ability to allow modules to generate methods names based
on a parameter might end up looking like some funky Ruby-template
language; and be both too much work to build and use (especially for
most code).

As my language also allows you to define both 'foo(a)' and 'foo(a, b)'
in a class and module, you might also want to change the signature of a
modules method so again it matches up. Like: 'foo(a)' to 'foo( a, _ )'
or 'foo( _, a )'.

But as you can reopen modules why not just do:

module Bar
def act()
update()
end

def foo( a, _ )
foo( a )
end
end

What might be nice is if you can apply it to any existing module without
that module needing to be aware that you are doing this. Something like:

class GameObject
include AI {
act() => update(),
foo(a) => foo( a, _ )
}
end

Then your restricting your changes to only affect it being mixed with
one class whilst not altering the module itself. That could be nice.
I like that idea, but don't really see how it is an advantage over just
having a class.

My thinking was that if you took my idea to the extreme then all your
code is built into modules. Classes then just become boiler plate for
mixing and setting up and initializing those modules. Having to write
boiler plate is a bad thing, so I'd like to find a way of avoid this.
But maybe this is leading to feature creep. Unless I can think of a more
natural way to mix modules, I'll skip this one.
def asteroid
Object.new.instance_eval do
extend Drawable # here it would be nice to be able to say :image =>
"images/asteroid.png"
extend MoveRandomly
extend DamagePlayer
self
end
end

In regards to the 'extend Drawable' bit, an idea is to add constructors
for modules which the compiler can then force the user to initialize,
like:

module Drawable
def new( img )
@img = img
end
end

class Asteroid
import Drawable

def new( img )
Drawable.super( img )
end
end
Anyway, good luck with it, but I would consider what changes you want to
make, and whether they really warrant creating an entirely new Ruby-like
language, or if the similarities are strong enough that just using Ruby
itself is satisfactory, ...

Thanks for all your suggestions. There are also some technical reasons
why I can't use Ruby itself. The main one is that it needs to run 100%
within the browser and your program then compiles to JavaScript. There
are some projects available already that allow you to run Ruby like
this, but most work by sending your code across to a server where it's
compiled and then sent back. Mine doesn't.

After I decided I had to make my own version I then thought I'd give in
and add lots of my own alterations that I'd like. null instead of nil,
'new' for constructors instead of 'initialize', C style comments, this
instead of self, function overloading instead of optional parameters,
and some static analysis and error checking during a compile time. I
used to program heavily in Java.

I'm also planning to add some type inference so you can only call
methods that might exist on the object your working with. With it being
less dynamic then standard Ruby, your program compiles directly to
JavaScript with very little runtime support needed. In theory your
program will run almost as fast as if you had written it in JavaScript.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Thanks for all your suggestions. There are also some technical reasons
why I can't use Ruby itself. The main one is that it needs to run 100%
within the browser and your program then compiles to JavaScript. There
are some projects available already that allow you to run Ruby like
this, but most work by sending your code across to a server where it's
compiled and then sent back. Mine doesn't.
Sounds really cool! I'll look forward to seeing it.
 
J

Joseph Lenton

Josh Cheek wrote in post #974852:
Sounds really cool! I'll look forward to seeing it.

There is actually an early proof of concept already online at:
http://playmycode.com/build/sandbox

But the language doesn't yet support some basics like inheritance, line
numbers for runtime errors (they are there for compiler errors), and
there are some performance improvements I need to get in.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Josh Cheek wrote in post #974852:

There is actually an early proof of concept already online at:
http://playmycode.com/build/sandbox

But the language doesn't yet support some basics like inheritance, line
numbers for runtime errors (they are there for compiler errors), and
there are some performance improvements I need to get in.
Whoah, this is way further along than I realized, I am incredibly impressed,
the language looks really good, too!
 
J

Joseph Lenton

Josh Cheek wrote in post #974877:
Whoah, this is way further along than I realized, I am incredibly
impressed,
the language looks really good, too!

Thanks! It's kinda on an open-unadvertised-beta at the moment until we
get all the core stuff finished (like crazy aspect mixins). But feel
free to sign up and build something.
 

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,708
Latest member
SherleneF1

Latest Threads

Top