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
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
