Support

If you have a problem or need to report a bug please email : support@dsprobotics.com

There are 3 sections to this support area:

DOWNLOADS: access to product manuals, support files and drivers

HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects

USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here

NEW REGISTRATIONS - please contact us if you wish to register on the forum

Mixing methods & non-methods in Ruby

For general discussion related FlowStone

Mixing methods & non-methods in Ruby

Postby HughBanton » Fri Jan 22, 2021 8:54 pm

A little bird told me that I've been mixing "def method" and "bare/non-method" Ruby code in my Ruby Edits. Shame on me ... :oops:

I'm hoping @Trogluddite can tell us all some more about this ;)

H
User avatar
HughBanton
 
Posts: 265
Joined: Sat Apr 12, 2008 3:10 pm
Location: Evesham, Worcestershire

Re: Mixing methods & non-methods in Ruby

Postby trogluddite » Sat Jan 23, 2021 1:39 am

HughBanton wrote:Shame on me ...

Nothing for anyone to be ashamed about - given the sparsity of FS Ruby guides and examples, people are making perfectly reasonable assumptions for the most part (there's a special place in hell for people who describe any coding language as "intuitive"!). I was just reviewing what the User Guide has(n't) got to say about this subject, and quite honestly, consulting a ouija board, some chicken entrails, and the I-ching would probably be about as useful! The disclaimer that the Ruby chapter "assume[s] a basic knowledge of the Ruby language which is not covered in this guide" doesn't cut it, IMHO, as this is very FlowStone specific knowledge that you won't find anywhere else online. The poor old "init" method (troublemaker in your Slack example) doesn't even get a polite introduction - it suddenly appears out of nowhere in an example demonstrating a completely unrelated concept, without so much as a nod to what it's there for! GRRrrrr! :evil:

Watch this space - tutorial to follow shortly...
All schematics/modules I post are free for all to use - but a credit is always polite!
Don't stagnate, mutate to create!
User avatar
trogluddite
 
Posts: 1727
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

Re: Mixing methods & non-methods in Ruby

Postby HughBanton » Thu Feb 11, 2021 12:16 pm

I've gleaned quite a bit about my method-use 'error', since displaying it the other week, and maybe gained some insight. (Got rid of the phantom error anyway!)

My primary misconception, I think, was that anything inside 'def init' runs whenever a Ruby code block is called, in the same way that in DSP you can declare stage(0) to run first, and just once, whenever a new note is keyed. I now suspect that's fundamentally wrong about 'init', no?

And secondly - and bear in mind I'm a pretty inexperienced coder - in other languages, a block that's a 'Method' (or a 'Function', 'Sub-routine', etc) always gets called from somewhere else. However there are plenty of Ruby examples we encounter which seem to be 100% def 'this' & def 'that', but where nothing seems to get actually called!

From which I assume that Flowstone Ruby always runs a method such as def 'mouseLdown x,y' in the same way as it always runs def 'event x,y', because the calling is external.

So is it actually wrong to write :
Code: Select all
def add(a,b)
   return a+b
end
add(2,1)

Which I would consider .. 'conventional'? (Or is my write wrong! :oops: )
H
User avatar
HughBanton
 
Posts: 265
Joined: Sat Apr 12, 2008 3:10 pm
Location: Evesham, Worcestershire

Re: Mixing methods & non-methods in Ruby

Postby tulamide » Fri Feb 12, 2021 12:00 pm

I hope you don't mind that I step in for trog, who is currently absent on the forums.

HughBanton wrote:My primary misconception, I think, was that anything inside 'def init' runs whenever a Ruby code block is called, in the same way that in DSP you can declare stage(0) to run first, and just once, whenever a new note is keyed. I now suspect that's fundamentally wrong about 'init', no?
Yes, it is wrong. Don't compare DSP to Flowstone Green to Ruby. They are all different, they work different and they don't share anything other than that their output can be used by each other. All three are black boxes to each other, they run in parallel but not collectively. Either of them could stop running with the other two completely fine continuing running. To understand Ruby better, don't try to find parallels, but see Ruby as a programming language on its own. Ruby is built from classes, which means that everything is an object called "class". This is true for everything, including a RubyEdit (the red Ruby code editor). Every object has an initialization method, which is called by Ruby when a copy of classs definition is instantiated. A RubyEdit is instantiated, when you drag it into the schematic, when you write code into it, and when you load a schematic with a RubyEdit inside. The class definition for a RubyEdit does its own initialization tasks (as programmed in Ruby by DSPR) and then calls a method named "init". If the method doesn't exist (because you didn't write one), it's ignored. If it exists, the contents are executed. That's all there is to it. A one time initialization option, when the class instance is created.

Btw., A Ruby Code Block is something very specific. I know that you didn't mean that one, but a "code block" object does exist in Ruby. It is often used as an alternative to passing arguments. Instead of values, code that's executed is passed. You will recognize a code block by either "{ somecode }" or "do somecode end"

HughBanton wrote:And secondly - and bear in mind I'm a pretty inexperienced coder - in other languages, a block that's a 'Method' (or a 'Function', 'Sub-routine', etc) always gets called from somewhere else. However there are plenty of Ruby examples we encounter which seem to be 100% def 'this' & def 'that', but where nothing seems to get actually called!
No that's not true. The class definition of a RubyEdit is code that you don't get to see (instead you see the red Ruby editor). It's that code that calls the methods you define. The code does it using a bridge from Flowstone's internal C/C++ routines that are passed to the class. So, when you move your mouse, Flowstone informs the RubyEdit that the mouse has moved, the RubyEdit then calls "mouseMove()", and if you created a mouseMove definiton in your RubyEdit instance, its content is executed. If it doesn't exist, it is ignored.

HughBanton wrote:From which I assume that Flowstone Ruby always runs a method such as def 'mouseLdown x,y' in the same way as it always runs def 'event x,y', because the calling is external.
No. Ruby just like Green, is event driven. Only if an event happens, Ruby reacts. So "def mouseLDown()" is called, when the left mouse button was actually pressed. Flowstone however does indeed run in a continuous loop to catch all those events and redirect them to Green, Blue and Red.

HughBanton wrote:So is it actually wrong to write :
Code: Select all
def add(a,b)
   return a+b
end
add(2,1)

Which I would consider .. 'conventional'? (Or is my write wrong! :oops: )
H
No, it is not wrong. The RubyEdit instance is there for you to do, whatever you seem fit. However, what would this particular code help you with? You define no variable to hold the result from your method, so it's put into the info pane and is then forgotten.


You are at a point on your Ruby journey, where I strongly advise to read chapter 8 of the user guide. It contains all of the information you need regarding how Ruby works. Most of your questions are actually answered in chapter 8. It also prevents you from assuming things, which is a dangerous path to go on the long run!
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2686
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Mixing methods & non-methods in Ruby

Postby HughBanton » Mon Feb 15, 2021 7:18 pm

All most interesting, thanks tulamide. (Sorry about "code block" - I'm familiar with {..} and I should have known that!)

I do regularly refer to chapter 8, however I rarely do any graphics stuff so in truth my preferred Ruby resource is generally Google, such as .. "ruby insert a character" or "ruby join an array" - almost always finds me the answers I need!

But as Trog rightly said, an explanation of 'def init' is sadly lacking in the FS guide, and I confess I'm still slightly unclear how it works. The code I'd put up (that created a 'phantom error' in Alpha) had an array defined inside a def init, and then I used bare code to use that array to index another array which came in through an input.

I fixed it by making the whole thing into a 'def event i,v' instead. But I remain unclear why the original was suspect.

H
User avatar
HughBanton
 
Posts: 265
Joined: Sat Apr 12, 2008 3:10 pm
Location: Evesham, Worcestershire

Re: Mixing methods & non-methods in Ruby

Postby tulamide » Tue Feb 16, 2021 1:55 pm

HughBanton wrote:All most interesting, thanks tulamide. (Sorry about "code block" - I'm familiar with {..} and I should have known that!)

I do regularly refer to chapter 8, however I rarely do any graphics stuff so in truth my preferred Ruby resource is generally Google, such as .. "ruby insert a character" or "ruby join an array" - almost always finds me the answers I need!

But as Trog rightly said, an explanation of 'def init' is sadly lacking in the FS guide, and I confess I'm still slightly unclear how it works. The code I'd put up (that created a 'phantom error' in Alpha) had an array defined inside a def init, and then I used bare code to use that array to index another array which came in through an input.

I fixed it by making the whole thing into a 'def event i,v' instead. But I remain unclear why the original was suspect.

H

I see.
But let me start by saying that, yes, there is no "teaching Ruby" in chapter 8. And quite a few things are missing even in the part that IS supposed to be covered by the chapter. But chapter 8 contains an awful lot of information about how to use the communication between Ruby and other parts of Flowstone, like green and blue.

When I started with Flowstone, I had no idea of Ruby. I never heard of the language before and never worked with it. I do have a background in programming (as a hobby, not professionally), covering modern Basic or visual dialects like .net from Microsoft, and scripting languages like Python.
Yet, just by reading chapter 8 and toying around in a RubyEdit, I was able to learn to use Ruby basically. I then extended my knowledge about Ruby using the official documentation about Ruby 1.9.3, which is used in Flowstone before the alpha. You can visit it here: https://ruby-doc.org/core-1.9.3/
It needs you to know about the existence of the two main building blocks of Ruby, classes and methods. Everything is well documented.

What I want to say with the last paragraph is, that despite its flaws, chapter 8 is a very helpful resource and provides a lot of information. It even covers exactly the case you made in your post :mrgreen:
Basically, there's a difference between creating a method for direct use, like the example you made with add(), and using an existing method like init() to set up variables. Also, without event() you won't be noticed when a value arrives at one of the inputs. You would just run your code once right after the instance was created, with whatever value is at the input at that time (which could very well be no value or nil, and that will give you trouble galore)

The non-programming (and not very accurate, but helping) answer would be "if you use init() you have to use event() as well"

To understand why there are existing methods, although you yourself write the code for it (like init(), event(), etc), forget about Flowstone for a second. Everything in Ruby is a cass. I probably said that 6.9 billion times over the years, but it really is key to understanding Ruby.

A class is a construct, a template, that is filled with methods.
Code: Select all
class Calculator
  def add(a, b)
    return a + b
  end
end

We then create an instance of the class, which we use.
Code: Select all
class Calculator
  def add(a, b)
    return a + b
  end
end

calc = Calculator.new
calc.add(2, 3)

But what is this method "new"? It is a very specific one, a method you can't create, delete, alter or extend. It orders Ruby to do two things:
1) Allocate memory for the instance that will be created
2) Call the instance's initialize method.

Whenever you use Class.new, you call initialize() of the new instance. Our Calculator has no such method. That's fine, Ruby just ignores it then. But if we create one, it will be called and its content executed.
Code: Select all
class Calculator
  def initialize
    @ha_we_falsify_add = 10
  end
  def add(a, b)
    return @ha_we_falsify_add + a + b
  end
end

calc = Calculator.new
calc.add(2, 3)

Do you see a pattern emerging? If not, you will soon.
We can code whatever we like in initialize(). Let's call another method!
Code: Select all
class Calculator
  def initialize
    @ha_we_falsify_add = init()
  end
 
  def init
    return 10
  end
 
  def add(a, b)
    return @ha_we_falsify_add + a + b
  end
end

calc = Calculator.new
calc.add(2, 3)

And now comes the funny part. Something that only works in Ruby. At any point in time, we can re-visit our class definition and alter a method.
Code: Select all
class Calculator
  def initialize
    @ha_we_falsify_add = init()
  end
 
  def init
    return 10
  end
 
  def add(a, b)
    return @ha_we_falsify_add + a + b
  end
end

class Calculator
  def init
    return 999
  end
 
  def sub(a, b)
    return a - b
  end
end

calc = Calculator.new
calc.sub(3, 2)
calc.add(2, 3)

Cool, isn't it? We changed a method and added another one. In a totally independend block of code with the same name of the class! In this example we've put both class definitions one after the other, but in reality, you can put it wherever you like. All it needs is an init() method already existing, to override its content.
Do you now see a pattern emerging?
The programmer of DSPR did the very same thing. In the initialize method of the RubyEdit class, he placed a call for the init() method he created in the code (just like us, see above), which will be executed during initialization of the instance (which is the Ruby editor you dragged into the schematic). Nobody keeps us from changing the content of init() by creating our own init() method!

The only difference is that you don't get to see the code, where the init method is defined. In our example it would be that you couldn't see the whole "class Calculator ... end" definition. Instead you define the method as if you were inside of the class definition (which you somehow are). "def init" right into the editor, because you write from within the RubyEdit class.

I know that I am no trog, he could find better words to describe it, and my vocabulary is of course restricted as English is my second language, but I hope it helped a little bit. At least to try out a few things, before Trog returns and explains it more detailed :D
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2686
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Mixing methods & non-methods in Ruby

Postby HughBanton » Wed Feb 17, 2021 5:45 pm

Ah, yes, thanks - I can honestly say that I think the penny has dropped! (Or is dropping, anyway ...)

I was slightly confused that you'd made me a Calculator that produces wrong answers(!), nor did I know that 'Calculator' was an existing Ruby class. (Although I suppose one could have laid bets that it was). Oh, and that there's a method up above called 'initialize' that can contain one called 'init'. Sorted a bit now.

Having got past those three this all makes a great deal of sense, much better than some of Chapter 8, thank you! In Chapter 8, the crucial pair of phrases: "– everything is an object. Each object is an instance of some class" don't appear until your'e 16 pages in, when discussing Ruby values.

Very easy to skip over this bit when starting out. Now obviously I've often heard the phrase "everything is an object" .. but that inevitably leads to "so - what is an object, then?" (If not a fuse-holder, or a shoelace, or .. :lol: ) I find Chapter 8 often makes statements that only make sense if you already know what they meant in the first place. Which hopefully I do a bit now.

I've started looking at the concurrent post "Ruby Class help" as well, clearly relevant to all this. I shall try to absorb ..

A grateful customer gave me a Rasberry Pi at Christmas, (I'd been acting as his free organ-electronics helpline all year). A solution in search of project ispiration so far! So, should I skip Python and install Ruby on it .. once I've thought of an application?

H
User avatar
HughBanton
 
Posts: 265
Joined: Sat Apr 12, 2008 3:10 pm
Location: Evesham, Worcestershire


Return to General

Who is online

Users browsing this forum: Google [Bot] and 36 guests