-1

I am writing a reader for an embroidery machine file format in Ruby, which has two types of stitches:

  • Regular stitches: Have a color and relative coordinates.
  • Jump stitches: Also have a color and relative coordinates, but they are not visible (threads will be removed by hand in the final embroidery and are not visible in any previews that may be generated) and coordinate changes are usually much larger than for regular stitches

In Java, I would probably use an abstract base class "Stitch" and two classes "JumpStitch" and "RegularStitch" inheriting from it. I would then use either quick and dirty instanceof or overloaded methods (handle(JumpStitch stitch), handle(RegularStitch stitch) or something like that) to do something with those (I need the distinction between regular stitches and jump stitches).

How would you achieve something similar in Ruby (as Ruby lacks method overloading and instance_of? being a big nono according to https://stackoverflow.com/a/3893403/3818564)?

Two use cases incorporated from my comments below:

I have a list of all consecutive stitches in a List - some of them are of type RegularStitch, the other ones of type JumpStitch. Now I want to do something with this list. Say, draw a preview. I am iterating through the list, and decide what to do based on the type of the stitch: RegularStitch will be drawn with the given color, JumpStitch will not be drawn (but the coordinates will be updated from it as they are the basis for the following stitch). – no-trick-pony 22 mins ago

Another example: I want to actually operate an embroidery machine. I can operate the machine faster, when there are only regular stitches (of the same color), but have to slow down the machine if a JumpStitch is next. I hope that clarifies my intentions.

Community
  • 1
  • 1
  • 5
    Err, Ruby doesn't lack those things. Your question is based on a fundamental misassumption. – user229044 Aug 12 '14 at 18:23
  • @meagar I think what he meant to say was that the use of `instance_of?` is discouraged in Ruby, which it is. – Ajedi32 Aug 12 '14 at 18:26
  • The answer you linked to recommended using polymorphism. Why not do that? – Ajedi32 Aug 12 '14 at 18:27
  • Huh.. I looked that up before asking my question and found http://stackoverflow.com/a/9373811/3818564 Could you please explain, how you think this might be achieved? – no-trick-pony Aug 12 '14 at 18:27
  • @Ajedi32: Polymorphism is what I wanted to use (via method signatures).. it is not possible in Ruby. Duck typing is not polymorphism since it does not operate with types. I also have no idea of how I would be able to achieve something like this in a clean way – no-trick-pony Aug 12 '14 at 18:30
  • 1
    I think you need to show a little more of how you would use these classes in order for the question to be answerable – Frederick Cheung Aug 12 '14 at 18:35
  • @FrederickCheung Thanks! :) I incorporated the two use cases I have given in reply to Nick Veys into the description. – no-trick-pony Aug 12 '14 at 19:06

1 Answers1

3

I'd argue your handle(JumpStich) and handle(RegularStitch) are poor uses of OO design in the first place. What's the point of having different types if they don't contain behavior?

Why does this not work?

class Stitch

  attr_accessor :color, :coordinates

  # ... common behavior

end

class RegularStitch < Stitch

  def foo
    # regular stitch behavior
  end

end

class JumpStitch < Stitch # or RegularStitch?

  def foo
    # jump stitch behavior
  end

end

Your Reader class creates instances depending on the data it reads. We don't know enough about what this foo means, so I can only guess, but this is one of the whole points of polymorphism.

Nick Veys
  • 23,458
  • 4
  • 47
  • 64
  • I describe the idea for Java here: I have a list of all consecutive stitches in a List - some of them are of type RegularStitch, the other ones of type JumpStitch. Now I want to do something with this list. Say, draw a preview. I am iterating through the list, and decide what to do based on the type of the stitch: RegularStitch will be drawn with the given color, JumpStitch will not be drawn (but the coordinates will be updated from it as they are the basis for the following stitch). – no-trick-pony Aug 12 '14 at 18:39
  • Other example: I want to actually operate an embroidery machine. I can operate the machine faster, when there are only regular stitches (of the same color), but have to slow down the machine if a JumpStitch is next. I hope that clarifies my intentions :) – no-trick-pony Aug 12 '14 at 18:40
  • 2
    Nick Veys's answer satisfies your requirement. When you're iterating through the list of JumpStitch and RegularStitch objects, you call the `foo` method on each one, and depending on what kind of stitch it is, the corresponding `foo` method is called. One method draws the stitch object in its given color (coming from its superclass) and the other doesn't. – Ege Ersoz Aug 12 '14 at 18:49
  • But then I have arbitrary functionality in classes that are meant to just store stitching data (entity-class like). Is that okay in the Ruby world? If so, I will gladly accept this solution (it's not about finding _any_ solution, but finding one which would be considered good practice in the Ruby world). :) – no-trick-pony Aug 12 '14 at 18:53
  • 1
    For the first question, I'd do this: `stitches.each(&:preview)`, where there is a `#preview` method on both `JumpStitch` and `RegularStitch`, and they do the right thing. For the second question, I'd maybe do something like: `stitches.each { |s| s.apply_machine_settings(machine); s.do_stitch }`. It's hard to say without more details but hopefully you get the gist of it. The behavior should lie within the stitch, or allow it to delegate that behavior somewhere else in a simple way. – Nick Veys Aug 12 '14 at 18:54
  • Classes that just store data are structs. By definition a class is data *AND* behavior. If you're missing out on the behavior part you're really crippling your objects and making your solution more spread out. – Nick Veys Aug 12 '14 at 18:55
  • And just because the method to ask for the work to be done is on the `XXXStitch` classes, doesn't mean the *implementation* of that method need be there, it can delegate out to classes that know better or whatever... But from a high level, objects should appear smart and do useful stuff! – Nick Veys Aug 12 '14 at 18:56