Sonic Pi lang, Ruby and the eval

Sonic Pi is said to be a language “based on” or “derived from” Ruby. Trying to better understand how the Runtime interprets and executes the code I found that (correct me if I’m wrong) at the end of a lot of smart code there’s a call to the Kernel.eval() method.

I suppose something magic happens before or after that evaluation that makes Sonic Pi a domain specific subset of Ruby, as stated elsewhere (e.g. the thread about using classes in Sonic Pi).

I’m not an expert with Ruby so I wasn’t able to follow the whole code evaluation mechanism and how syntax constraints are set, but I’m curious to understand how it works.

1 Like

Hi, @giohappy !

I believe your assumption that Sonic Pi is merely “based on” Ruby is not correct, that is, Sonic Pi uses a genuine Ruby interpreter to evaluate your code (that is what eval does). You can, for instance, define your own modules, classes, and methods, at least last time I tried it.

That said, I cannot guarantee that you will not manage to crash the application if you do weird stuff with threads or massively hack the core Sonic Pi classes :slight_smile:

Thanks for clarifying @shemp. So I suppose the discussion in this post relates to the threading issues that my arise when using (naive) classes.
I was misleaded by reading that they might work (at the time) but they’re not guaranteed to work in future versions, etc.

What I gather from that thread is, there is no specific mention of object-oriented programming techniques, use of Ruby classes, etc. in the online Help tutorial in Sonic Pi. However, the thread does not mention any specific bugs or incompatibilities, and indeed you can run the type of code there like

MAIN = self

class BassTest
  attr_accessor :note
  attr_accessor :synth
  
  
  def playit
    use_synth @synth
    play @note
  end
  
  def initialize(note=60)
    @note = note
    @synth = :blade
  end
  
    def method_missing(method, *args)
    if MAIN.respond_to?(method)
      MAIN.send(method, *args)
    else
      super
    end
  end
  
  
end

bb = BassTest.new

live_loop :loop_A do
  bb.playit
  sleep 4
end

sleep 8
bb.note = 67
bb.synth = :chiplead

and it works. Not that this is an especially useful example, but it shows that Ruby is interpreted as usual even if not discussed in the official Lang tab.

1 Like

Reading again the following statement from @ethancrawford, I understand thar he refers to the official Sonic Pi documented language. One day it might be implemented with a different system / language (e.g. Erlang) so any custom Ruby code would stop working.

Using custom classes is not possible using the officially supported Sonic Pi syntax. Such a thing is potentially doable using vanilla Ruby syntax, which Sonic Pi’s API is built on, but there is no guarantee that if it works, it would continue to work in future versions.

1 Like

Correct. @shemp - whether classes, modules etc work is not guaranteed - there are certain ways the Sonic Pi server/runtime code is constructed that means that not all plain Ruby code will necessarily work. @samaaron will know more about this in detail.

As @giohappy alludes to, one day there is a possibility that the Sonic Pi language may be rewritten in another base language altogether as well. This is definitely still a very long way away if it does end up happening however, and if it did, we would be giving everyone plenty of notice.

@ethancrawford Since the evaluation of code is performed with a standard eval, I suppose that plain Ruby code might fail because of the way the runtime takes control of threads, thread locals, the scheduling, etc., right?

Yes, though it’s also through things like namespacing.