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

Users are reminded of the forum rules they sign up to which prohibits any activity that violates any laws including posting material covered by copyright

Ruby Class help

For general discussion related FlowStone

Re: Ruby Class help

Postby tulamide » Mon Jan 04, 2021 6:13 pm

adamszabo wrote:All this info needs to sink in before I actually understand it, I need to practice before I can continue. :lol:

What I mean with the outputs, if I write this in the class:

Code: Select all
def testout
    output 0, 1
end


and then I call it in a different rubyedit

Code: Select all
@shape.testout


Shouldn't it call that function and send "1" to the first output in this other rubyedit?

No.
The reasons were explained very good by trog, and I would have a hard time to add anything to it. Remember, output is an instance method of the RubyEdit class and therefore you can't call it from within another class. Only by referencing similar to what trog explained, can you get some basic access to the output method.
This is just a quick answer, and maybe trog has to correct something or can add something. But your approach won't work. You could pass the reference to an output to your method, which could work. See trogs explanations.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Ruby Class help

Postby adamszabo » Mon Jan 04, 2021 8:25 pm

Ok, thanks for clearing it up!
adamszabo
 
Posts: 667
Joined: Sun Jul 11, 2010 7:21 am

Re: Ruby Class help

Postby trogluddite » Mon Jan 04, 2021 9:56 pm

adamszabo wrote:All this info needs to sink in before I actually understand it, I need to practice before I can continue.

Honestly, do that - I had to plenty of times when I was learning Ruby! There is a steep bit of the learning curve for the "which method? what data? who is the receiver?" stuff for a lot of people when they first get stuck into the true "object oriented" use of Ruby. Like I had, you've also spent a long time learning other kinds of coding before getting this deep into Ruby, and TBH, I think that hinders as much as it helps - so much of Ruby looks really, really similar to concepts that you know from elsewhere, so it can be hard to see them from another angle at first. It took me quite a few attempts before the whole "object oriented" thing clicked into place.

One thing I would advise is to leave the close integration with RubyEdits aside for now, as I think it's confusing matters. I can understand why that's your goal, but it's hard to learn the general rules from objects which are so unusual. Part of the reason why I've been so slow working on the GUI objects you asked me for is that I keep on finding bizarre implementation details of RubyEdits and other internal classes that sabotage my plans (I'm also incredibly lazy and unreliable, of course! :oops: )

In part, that's just how FS is, it generally favours making things relatively simple for non-coders at the expense of making the hard stuff harder. But that fits with the general FS philosophy, I suppose - graphical patching is still the main USP, despite all the other goodies we have.

Rather than batter you with any more right now (I know, I just don't know when to shut up sometimes!), I'll let you have a little sinking in time - there is a heck of a lot in this thread for anyone to comprehend in so little time. When you want to move on, just post again - we're still in Covid lockdown, so I won't be going anywhere! :lol:
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: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

Re: Ruby Class help

Postby tulamide » Mon Jan 04, 2021 11:11 pm

trogluddite wrote:Part of the reason why I've been so slow working on the GUI objects you asked me for is that I keep on finding bizarre implementation details of RubyEdits and other internal classes that sabotage my plans (I'm also incredibly lazy and unreliable, of course! :oops: )

We share that. My anxiety disorder makes me unreliable as well. It often is too much (not really, but in my mind) and so I abandon the work, hoping, I get better and continue to work.

On a more serious note, since you've mentioned GUI objects, I hope we don't work on the same things without knowing from each others work? That would be ... sub-optimal.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Ruby Class help

Postby adamszabo » Mon Jan 04, 2021 11:36 pm

I asked Trog to give a hand with a knob Class, but I see if I can manage to make most of it, and learn in the process. After that I plan to do the user skins for Viper, and I plan on doing that as well, but you are welcome to beat me to it before I get there :lol:
adamszabo
 
Posts: 667
Joined: Sun Jul 11, 2010 7:21 am

Re: Ruby Class help

Postby tulamide » Tue Jan 05, 2021 8:58 am

Oh, I see. Well, I'll step back from the knob class and concentrate on the skin. Good to know that there is less for me to worry about. Let the race begin :lol:
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Ruby Class help

Postby adamszabo » Mon Jan 11, 2021 12:15 am

Ok so I have been messing about a bit and I translated Trogs 'MouseRect' class which was posted previously into a module which seems to work:

Code: Select all
module MRect
    def MRect.initialize(color, area)
        @brush = Brush.new(color)
        @position = area
    end

   def MRect.draw(view)
      view.drawRectangle(@brush, @position)
   end
   
   def MRect.mouse_over?(mx, my)
         x, y, w, h = @position
         mx.between?(x, x + w) && my.between?(y, y + h)
    end
end

def init
   MRect.initialize(Color.new(200, 0, 0), [2, 2, 5, 5])
end

def draw(view)
    MRect.draw(view)
end

def isInMousePoint(x, y)
    MRect.mouse_over?(x, y)
end


Now the question is, which is better? Lets say I draw several squares in many different ruby edits but I only want to change their color. I can either call that class or the module and only change the color values. But will the class use more memory since it creates new square and the module only draws the existing square? which is better?
adamszabo
 
Posts: 667
Joined: Sun Jul 11, 2010 7:21 am

Re: Ruby Class help

Postby trogluddite » Mon Jan 11, 2021 5:33 pm

adamszabo wrote:Now the question is, which is better?

The Class is better. That way of using a Module is just not what Modules are meant to be used for, and is poor Ruby code - the example is precisely the kind of problem for which Classes and their instances were invented. Effectively, you are trying to force an object-oriented language (Ruby) to be an imperative language (e.g. DSP-code, Pascal). Please, forget Modules for the time being - by allowing you to keep thinking in terms of "functions" instead of "objects", they are seriously leading you along the wrong path for learning Ruby.

adamszabo wrote:But will the class use more memory since it creates new square and the module only draws the existing square?

It will make very little difference to memory usage, and the Module is probably less CPU efficient.

Class instances ("objects") do two things: 1) They act as a container for a bunch of data all belonging to the same "thing". 2) They can perform a bunch of behaviours specific to that kind of "thing" (which may or may not modify the contained data). So, in the Class, each MouseRect object knows its own color, its own position, and how to draw itself at that position and in that color. This is called "encapsulation" - the idea that the outside code doesn't have to be cluttered with loads of trivial information about the objects, and doesn't need to correlate data from multiple sources - you create the objects with their own data (and only their own data) already inside them, and then they carry it around with them (even if, say, you send them via Ruby links to another module).

If you use a Module, the memory use will be roughly the same, because the colours and positions still have to be stored persistently somewhere - e.g. in @instance_variables of each "hosting" RubyEdit. And whenever you want to draw a different rectangle, you first have to modify the Module by moving data from your external storage into the Module (of course, there is some data movement for instances of a Class, too - but the Ruby "engine" does this "under the hood" much more efficiently than written-out lines of code ever could). In fact, for this case, the Module is the worst case scenario - you're basically just using "draw" as a stand-alone "function", so you may as well define draw to take "color" and "position" as additional arguments, instead of indirectly passing them via instance variables and "initialize" (though the Class would still be preferable even to that).

Think of a user-guide for one of your plugins. You would naturally describe a complex GUI as having a "collection of mouse handles", "several envelope nodes", "a grid of cells", etc. - you wouldn't say to the end-user; "the GUI has a collection of active mouse areas denoted by rectangles drawn according to arrays of correlated position and colour data" (at least, I hope you wouldn't!). The idea of "object oriented" languages is that your code can "talk" that way too...
Code: Select all
# NB: Assuming the previous example definitions of MouseRect.

# Example1: MouseRect is a Module (not "object oriented").

def init
  @colors = [Color.new(0), Color.new(64), Color.new(128), Color.new(255)]
  @positions = [[0,0,1,1], [1,1,1,1], [2,2,1,1], [3,3,1,1]]
end

def draw(view)
  (0..3).each do |index|
    MouseRect.initialize(@colors[index], @positions[index])
    MouseRect.draw(view)
  end
end


# Example2: MouseRect is a Class (let's talk about rectangles!)
def init
  @rectangles = [
    MouseRect.new(Color.new(0),   [0 ,0, 1, 1]),
    MouseRect.new(Color.new(64),  [1, 1, 1, 1]),
    MouseRect.new(Color.new(128), [2, 2, 1, 1]),
    MouseRect.new(Color.new(255), [3, 3, 1, 1])
  ]
end

def draw(view)
   @rectangles.each do |rectangle|
     rectangle.draw(view)
   end
end

Note that...

- Inside Example2's "init", we are explicitly making rectangles - all of the information about a single rectangle is kept close together and there's a single collection of data (the Array) with a clear purpose described by its name. As the list of items get longer, or the amount of data per object increases, doing it like Example1 with separate tables which have to be correlated, becomes ever harder to manage (i.e. much easier to accidentally introduce bugs into!)

- Example2's "draw" method is now responsible only for drawing rectangles, and even if you're not so fluent in Ruby, the code pretty clearly says "draw each of these rectangles". OTOH, Example1 version is clumsy - it is doing a bunch of data correlation which has nothing to do with drawing, the multiple Array lookups are inefficient, and you need prior knowledge about the data in order to work out what it's for (very obvious knowledge in this case, but not every case is this simple!)

Object-oriented languages weren't invented in order to make code more efficient for the CPU or memory, and they rarely do. They were designed to make coders more productive and less prone to mistakes. The main idea is that the code better describes (to a human reader) the problem that is being solved - you are meant to use objects to hide the raw "nerd-speak" data and "functions", so that you can talk in terms of "objects" that are little models of the real-world things that they represent. It is possible to write Ruby code that behaves like a bunch of static functions, but doing it that way will always be an uphill struggle, because Ruby just isn't meant to work like that.
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: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

Re: Ruby Class help

Postby tulamide » Mon Jan 11, 2021 6:40 pm

trogluddite wrote:Object-oriented languages weren't invented in order to make code more efficient for the CPU or memory, and they rarely do. They were designed to make coders more productive and less prone to mistakes. The main idea is that the code better describes (to a human reader) the problem that is being solved - you are meant to use objects to hide the raw "nerd-speak" data and "functions", so that you can talk in terms of "objects" that are little models of the real-world things that they represent.

This!
For years I tried to bring this point to attention, as it is the path to understanding OOP. But whatever "course" I started it always ended with not connecting the dots.

Adam, also, don't think about "which is faster, uses more memory, etc. The first step is always to make it work in a comprehensible way within oop. You can later optimize code, if and where it needs some. But a language like Ruby already does a lot under the hood to provide good speed (of course not comparable to a compiled language, but within its limits). For example, there is a so called garbage collector ("gc", you will see this quite often in tutorials or on forums), which is a functionality that takes away the pain of allocating and freeing up memory for everything. It does that automatically in the background. No matter how many class instances you create, as soon as they aren't used anymore, they are marked and will be removed from memory automatically. Of course that doesn't mean it's always optimal. There are cases, where objects are created in such speed, that the gc can't keep up with it. For example when creating a new object everytime the mouse move triggers. In such situations it can be optimized (by keeping one object in memory instead of creating a new one each time, for example).
But this is better left for last. Concentrate more on human readable, comprehensible code. Guys like TheOm, trog, or even myself have published lots of code in that regard for you to have a look at in terms of structuring, class usage, object definitions in general, etc.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Ruby Class help

Postby trogluddite » Mon Jan 11, 2021 8:37 pm

tulamide wrote:But whatever "course" I started it always ended with not connecting the dots.

When I think back to first learning OOP, I'm always reminded of the old joke: (Visitor) "Excuse me, could you tell me the way into town?" - (Local Person) "Oooh; if I was going there, I wouldn't start from here!". The familiar-looking syntax made it hard for me to see that OOP is a different way even to think about code in the abstract sense. I made it hard for Ruby to be my friend because I wanted to be the same control-freak micro-manager that ASM had taught me to be! :lol:
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: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

PreviousNext

Return to General

Who is online

Users browsing this forum: No registered users and 51 guests