Strange error when exception occurs in Layout

Hello,

I encounter this strange error in my code. I stripped it down to this code:

(
// ERROR 
	{
		var window = Window.new;
		var layout;
		layout = VLayout(
			try {
				var x = Pn(nil.abcdef); // enclosed in any class
				Knob.new;
			} { arg error;
				"errrro".postln;
				Button.new;
			}
		);
		window.layout = layout;
		window.front;
	}.value
)

(
// No problem 
	{
		var window = Window.new;
		var layout;
		layout = VLayout(
			try {
				var x = nil.abcdef; // not enclosed in class
				Knob.new;
			} { arg error;
				"errrro".postln;
				Button.new;
			}
		);
		window.layout = layout;
		window.front;
	}.value
)

(
// decomposition: OK
	{
		var window = Window.new;
		var layout;
		layout = VLayout(
			Button.new,
			try {
				var x = nil.abcdef;
				var y = Ref(x);
				Knob.new;
			} { arg error;
				"errrro".postln;
				Button.new;
			}
		);
		window.layout = layout;
		window.front;
	}.value
)

The error is:

ERROR: Primitive '_QWidget_SetLayout' failed.
Wrong type.
RECEIVER:
Instance of TopView {    (0x55d478f0aa68, gc=84, fmt=00, flg=00, set=06)
  instance variables [35]
    qObject : RawPointer 0x55d45dcd28a0
    finalizer : instance of Finalizer (0x55d478f0ae98, size=2, set=1)
    virtualSlots : instance of Array (0x55d478300fd8, size=1, set=2)
    wasRemoved : false
    font : nil
    resize : Integer 1
    alpha : Float 1.000000   00000000 3FF00000
    decorator : nil
    layout : nil
    userCanClose : true
    deleteOnClose : true
    action : nil
    mouseDownAction : nil
    mouseUpAction : nil
    mouseEnterAction : nil
    mouseLeaveAction : nil
    mouseMoveAction : nil
    mouseOverAction : nil
    mouseWheelAction : nil
    keyDownAction : nil
    keyUpAction : nil
    keyModifiersChangedAction : nil
    keyTyped : nil
    focusGainedAction : nil
    focusLostAction : nil
    dragLabel : nil
    beginDragAction : nil
    canReceiveDragHandler : nil
    receiveDragHandler : nil
    toFrontAction : nil
    endFrontAction : nil
    onClose : nil
    onResize : nil
    onMove : nil
    window : instance of Window (0x55d47658e188, size=5, set=3)
}
PATH: /home/ggz/code/sc/seco/vlive/repeat/tests/bug_strange_try.scd

CALL STACK:
        MethodError:reportError
                arg this = <instance of PrimitiveFailedError>
        Nil:handleError
                arg this = nil
                arg error = <instance of PrimitiveFailedError>
        Thread:handleError
                arg this = <instance of Thread>
                arg error = <instance of PrimitiveFailedError>
        Object:throw
                arg this = <instance of PrimitiveFailedError>
        Object:primitiveFailed
                arg this = <instance of TopView>
        View:layout_
                arg this = <instance of TopView>
                arg newLayout = <instance of Ref>
        Window:layout_
                arg this = <instance of Window>
                arg layout = <instance of Ref>
        < closed FunctionDef >
                var window = <instance of Window>
                var layout = <instance of Ref>
        Interpreter:interpretPrintCmdLine
                arg this = <instance of Interpreter>
                var res = nil
                var func = <instance of Function>
                var code = "(
// ERROR strange
        {
                var ..."
                var doc = <instance of Document>
                var ideClass = nil
        Process:interpretPrintCmdLine
                arg this = <instance of Main>
^^ The preceding error dump is for ERROR: Primitive '_QWidget_SetLayout' failed.
Wrong type.
RECEIVER: a TopView

I say “strange” because if I put some object before, the error become a “new” call on this object:

^^ The preceding error dump is for ERROR: Message 'new' not understood.
RECEIVER: a Button


(
// ERROR
	{
		var window = Window.new;
		var layout;
		layout = VLayout(
			Button.new,
			try {
				var tmp = Ref(nil.abcdef);
				//var tmp = nil.abcdef;
				Knob.new;
			} { arg error;
				"errrro".postln;
				Button.new;
			}
		);
		window.layout = layout;
		window.front;
	}.value
)

Now I know how to workaround it but it’s a bit cumbersome to decompose each calls inside the try block

I’m on SC 3.11.1

I would avoid any decision making logic in a layout’s object list. If I needed a try in there, I would build an array of the layout’s arguments first (doing the try outside of the layout call), and then later passing that into VLayout(*theArgs).

That’s perhaps not a satisfactory answer, but there are known bugs with try within method calls. IMO at present it’s better to just not do it.

hjh

Thanks for the explanation :slight_smile: Since it’s a known bug, I will workaround it until fixed.

My usage is I create a Slider using a method .asSlider, and in this method, some things could fail depending on user input, so I put a try to avoid breaking everything. especially the SimpleController created that are never released due to the exception

Sounds like this one:

A wrapper class for GUIs… yeah, that’s a problem. Would you mind sharing some of the design of asSlider? Maybe there’s another workaround that can be folded into the method.

hjh

Would you mind sharing some of the design of asSlider? Maybe there’s another workaround that can be folded into the method.

Well this is not really needed, you have already been very useful, but since you ask ^^

Previously, this.spec.times[0] was in a Point in a env.grid_() call, now everything is isolated so it work as intented.

Here I could just test for the class of spec to avoid errors now that I know it is the most common cause of failure. But this would break polymorphism, and the goal of try is to be sure code recover from errors, even the ones I didn’t anticipate

asEnvelopeView {
	var view;

	view = FixedEnvelopeView.new(nil, Rect(0, 0, 230, 80))
		.drawLines_(true)
		.selectionColor_(Color.red)
		.drawRects_(true)
		.step_(0)
		.thumbSize_(10)
		.elasticSelection_(false)
		.keepHorizontalOrder_(true)
		.rightClickZoomEnabled_(true);

	try {
		var step = this.spec.times[0].unmap(1/8);
		var point = Point(step,1/8);
		var dur = this.spec.times[0].unmap(2);
		view.grid_(point);
		view.totalDur_(dur);
		view.gridOn_(true);
		view.mapParam(this); 	// should be after spec access which can fail

	} { arg error;
		"In: %.asEnvelopeView".format(this).error;
		error.reportError;
		if(this.spec.isKindOf(ParamEnvSpec).not) {
			"%.asEnvelopeView: spec is probably not compatible with EnvelopeView: %".format(this, this.spec).error;
		};
	};
	^view;
}

Hmm… Yeah, I don’t have any other ideas (except to gdb trace it and see where the stack goes haywire).

It’s an unfortunate bug, and unfortunately in a part of the code that isn’t well understood.

hjh

1 Like