Writing Classes - Inherited method not understood

Hello everybody!

I’d like to write a simple random walker Class, a class which draws a path on a UserView exactly as a Pen would. Hence it inherits from QPen.

Here a simplified version of the class deifnition:

Walker : QPen {
	var parent, <>x,<>y, <>color;

	*new {
		arg parent, x,y, color = Color.white;
		^super.newCopyArgs(parent, x,y,color)
	}

	display { // method to position it on the parent View
		this.moveTo(Point(this.x, this.y));
		this.stroke;
		^this
	}
}

and here a simple usage example:

(
w = Window.new.front;
u = UserView(w, w.view.bounds);
k = Walker(u, 10,10);
u.drawFunc_({
	k.display;
})
)

but I already get an error

^^ ERROR: Message 'moveTo' not understood.
RECEIVER: a Walker

I tried the same thing with super.moveTo, but it seems that super is a Walker anyway.
What am I missing?

Thank you!

What am I missing?

moveTo is a class method of Pen, not an instance method? (As is stroke, &etc).

Pen.new.moveTo // error

Pen’s a slightly unusual class.

There’s not really any need to make instances of Pen, and I’m not sure it helps to inherit from it.

You could write this.class.moveTo but it’s nicer to just write Pen?

I tried the same thing with super.moveTo , but it seems that super is a Walker anyway.

super is another name for this, it’s used to tell the interpreter to start the name lookup at this.class.superclass instead of this.class.

Class methods are at the meta class, so you’d want this.class not super.

Pen.new.class.class == Meta_Pen

1 Like

First – QPen is in the “backward compatibility” folder – i.e., old name, don’t use it.

Pen is the right one.

Second – rdd is right that Pen defines *moveTo and this is not automagically translated to moveTo (no *).

A concept from object-oriented programming: “is-a” vs “has-a.”

Usually the first thought about how to extend the behavior of a class is to inherit from it. Then, the new class is of the same class as the original. In SC, Walker.new.isKindOf(Pen) == true.

This sometimes leads to trouble. So there’s another way: “has-a.” You write a class with no class-tree relationship to the one you want to extend, and in your class, you use the original class. Your class implements the interface that you need.

“Has-a” fits your use case a lot better than inheritance.

I suggest that if you delete : QPen and write the methods that you want using Pen (but not trying to “be” Pen), you will have a much easier time.

hjh

1 Like

Thank you both for the cues!
I went for the “has-a”/Pen.moveTo solution and I have a working Walker now.

There are still a couple of things that are not clear to me though:

  • referring to

super is another name for this, it’s used to tell the interpreter to start the name lookup at this.class.superclass instead of this.class

when would you use super instead of this ?

  • There are a lot of class methods which refers to this as a class and not as an instance. How do you differentiate them to call a class method rather than an instance method?
    Signal for example: hanningWindow is a class method which returns a this.newClear filled with a sine, and newClear is a class method inherited from ArrayedCollection.
    So why in my first attempt calling this.moveTo is automagically translated in moveTo (no star)?

Thank you so much for your inputs! You saved me a lot of time.

when would you use super instead of this ?

perhaps see Eliot Miranda’s explanation? it’s quite concise…

https://scsynth.org/t/using-superperform/5286/3

How do you differentiate them to call a class method rather than an instance method?

you don’t!

this is always the receiver of the message

in Signal.hanningWindow it’s Signal and

Signal.isKindOf(Class) == true

in Signal.new.size the receiver of size is Signal.new and

Signal.new.isKindOf(Signal)

there are some abstract classes on the edges but the “metaphysics” is still more or less as in this diagram:

3.14.class == Float
42.class == Integer
Float.class.class == Class
Integer.class.class == Class
Class.class.class = Class

Float.superclass.superclass == Number
Integer.superclass.superclass == Number
Number.superclass.superclass == Object
Object.superclass = nil

Object.class.class == Class
Class.superclass == Object
1 Like

First, super is used in constructors to call the constructor of the base class, e.g.:

OutputProxy : UGen {
	var <>source, <>outputIndex, <>name;
	*new { arg rate, itsSourceUGen, index;
		^super.new1(rate, itsSourceUGen, index)
	}

Second, super is used to explicitly call a method of the base class. Typically this is necessary if the subclass wants to extend/wrap a method of the base class. Example:

Foo : Bar {
    doSomething { arg x;
        super.doSomething(x); // call original method of Bar
        // do some more things
    }
}
1 Like

Ps. SortedList.addAll is another illustration, it has calls to both this.add and super.add.

Pps. I learned how to write where super lookup actually begins, thisMethod.ownerClass.superclass.

Thank you all very very much for your explanations!