February 2, 2016 by Daniel P. Clark

Ruby: Bindings Across Inheritance

One thing you will find yourself needing to do is work across different scopes and in different ways.  I would like to show one way of modifying local variables by passing a Binding object.

Let’s say you’re going to write encryption classes and you’ll have different ways of encrypting and decrypting.  For these you will have some common methods among them so we should create a common class to be inherited.

Now each of these classes will need to define an encypt and decrypt method and they will have unique code for their kind of encryption.  But there will be some code that needs to be done in each object.  Like verifying the input is appropriate.

Let’s say the input needs to be a string and at least 4 characters long.  Now we can do part of the methods in the EncryptionCore and just super it like this…

And this would work.  Since this is not the job of the method, as described by the method name, to validate input it would be wise to move it to a private method.

Now since it is a private method we can reuse it for our decrypt method as well.  But the EncryptionCore class doesn’t actually encrypt and decrypt objects.  So having the methods encrypt and decrypt in it are misleading.

Also at this point we’ve moved the code to the private method and now have no need to call super since the private method is callable from the class that inherits it.  Let’s look at an example where the private method “modifies” a local variable.

The validation code works, but the local variables have not changed.  As you can see the error was raised properly but any local variables we try to modify aren’t being modified.

Now in comes Binding.  With Binding we can pass a working scope somewhere else in our code base to allow access to local variables.

See!  The local variable has been changed from the inherited class !  Now we can write as many different encryption type classes that we want that can reuse private methods in EncryptionCore and it can process our local variables within each methods scope!  Viola!  You’ve passed the binding from the inheriting class to the inherited one and set up whatever local variable changes you wanted.

Summary

It makes sense to separate parts that do and don’t belong.  When you’re writing a class for common methods to be inherited but have some methods that don’t belong in it – it becomes very useful to work with bindings across classes.  Each FluffyEncryption and ChewyEncryption classes define their own unique encrypt and decrypt methods which CoreEncryption doesn’t.  And you have the full power to share common processing code between them with passing in a  binding and setting/getting local variables.  This keeps the code clean, methods are where they belong and people won’t get confused with deceptive methods in CoreEncryption.

As always I hope you’ve enjoyed this!  Please comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Philippa Willitts via the Creative Commons Attribution-NonCommercial 2.0 Generic License

#binding#lexical scope#local variables#ruby#scope
  • Dmitrii Krasnov

    Local variable is changing inside validate_string_input, but method name says nothing about that change. I would say that this binding magic is even more confusing than write

    [/crayon]

    • Dmitrii Krasnov

      This is how I see this code:

      [/crayon]

      • I like your use of raising a “not implemented” error.

      • dhalai

        I definitely agree with you. In the first implementation `validate_string_input` has a side effect, which can be very confusing. By the way, thx Daniel for showing one more way.

    • Haha… magic 🙂 . I’ll change the name to reveal it’s function as you’ve indicated.

      One thing I really don’t like about binding is that I have to use it in the scope it’s from as a parameter. What I really want is something like the gem binding_of_caller so that I can monkey with the caller’s scope. But that would probably be bad language design as far as Ruby is concerned. It’s best to protect scopes.

      I like the assignment of

      less than

      as far as appearance goes so that’s personal preference. Private methods are where the ugly looking code should go… not the front facing public methods.

      I’m merely demonstrating another part of the Ruby language available to us all.