Naming a new block "constructor" will break the editor

I just found this very odd bug. Here is how to reproduce it.

  1. Create a new block named "constructor" (case sensitive) in any category. It can be a command, reporter, or predicate.
  2. The make a block window will not close when you press OK, and the block will not show up on the left.
  3. Press cancel on the make a block window
  4. Click to another category.
  5. Click back to the category the "constructor" was created in. The pallet will be blacked out, and blocks cannot be taken out of it.

This problem is persistent. Saving and loading the project will not fix it. I am currently using 10.0.13 on this website. Is the something known about? Are there any other words to avoid? Thanks!

Here is a project demonstrating the bug (check "Control" and "Constructor" category)

The link to the project doesn't work. You probably didn't share the project.

Oops! Here is a working link:

If this doesn't work, check my profile or create a new project and follow the steps above.

That one worked.

Yeah, that's extremely odd. Aside from the lack of blocks in the constructor and control category, some other weird stuff seems to happen as a result. You can't seem to make custom blocks, importing libraries makes it freak out, and when I import a library that adds a category, it completely covers the icons in the top left corner, rendering them unusable, and impossible to interact with. I'm not sure why this is, but it's certainly an interesting bug.

Welcome to the forum!

That's an amazing bug. Thanks for reporting it.

I checked the console while creating a "constructor" block, and followed an error to this.

        // look up the spec
        info = this.labelParts[spec];
        if (!info) {
            throw new Error('label part spec not found: "' + spec + '"');
        }

        // create the morph
        switch (info.type) {
        case 'input':
            part = new InputSlotMorph(null, null, info.menu);
            part.onSetContents = info.react || null;
            break;
        case 'text entry':
            part = new TextSlotMorph();
            break;
        case 'slot':
            part = new ArgMorph(info.kind);
            break;
        case 'boolean':
            part = new BooleanSlotMorph();
            break;
        case 'symbol':
            part = new BlockSymbolMorph(info.name);
            part.size = this.fontSize * (info.scale || 1);
            part.color = info.color || WHITE;
            part.shadowColor = this.color.darker(this.labelContrast);
            part.shadowOffset = MorphicPreferences.isFlat ?
                    ZERO : this.embossing;
            part.fixLayout();
            break;
        case 'c':
            part = new CSlotMorph();
            break;
        case 'command slot':
            part = new CommandSlotMorph();
            break;
        case 'ring':
            part = new RingMorph();
            part.color = SpriteMorph.prototype.blockColor.other;
            part.selector = info.selector;
            part.setSpec(info.spec);
            part.isDraggable = true;
            break;
        case 'ring slot':
            switch (info.kind) {
            case 'command':
                part = new RingCommandSlotMorph();
                break;
            case 'reporter':
                part = new RingReporterSlotMorph();
                break;
            case 'predicate':
                part = new RingReporterSlotMorph(true);
                break;
            default:
                throw new Error('unknown ring kind: "' + info.kind + '"');
            }
            break;
        case 'template':
            part = new TemplateSlotMorph(info.label);
            break;
        case 'color':
            part = new ColorSlotMorph();
            break;
        case 'break':
            part = new Morph();
            part.setExtent(ZERO);
            part.isBlockLabelBreak = true;
            part.getSpec = () => '%br';
            break;
        case 'variable':
            part = new TemplateSlotMorph(info.label);
            part = new ReporterBlockMorph();
            part.category = 'variables';
            part.color = SpriteMorph.prototype.blockColor.variables;
            part.setSpec(localize('Input name'));
            break;
        case 'multi':
            part = new MultiArgMorph(
                info.slots,
                info.label,
                info.min || 0,
                spec,
                null, null, null, null, null,
                info.infix,
                info.collapse,
                info.dflt,
                info.group
            );
            part.maxInputs = info.max;
            part.initialSlots = Math.max( // this needs some fixing
                part.initialSlots,
                isNil(info.min) ? 0 : +info.min,
                isNil(info.defaults) ? 0 : +info.defaults
            );
            for (i = 0; i < info.defaults || 0; i += 1) {
                part.addInput();
            }
            break;
        default:
            //error is thrown here
            throw new Error('unknown label part type: "' + info.type + '"');
        }

This seems to suggest the the constructor block is empty, and has no lables or inputs. I downloaded the project's XML and took a look at it.

<block-definition s="constructor" type="command" category="Constructor">
	<header></header>
	<code></code>
	<translations></translations>
	<inputs></inputs>
</block-definition>

This looks like it is empty and broken, but here is what a working block with only one text lable and no inputs looks like.

<block-definition s="myNewBlock" type="command" category="control">
	<header></header>
	<code></code>
	<translations></translations>
	<inputs></inputs>
</block-definition>

Very odd. This looks basically the same.
My best theory so far is that the name "constructor" somehow creates a block that has no labels or inputs, that isn't render-able.

Except for the part about category="Constructor".

I think you're seeing two separate problems. The one about what's in the project's XML is the result of the make-a-block dialog failing, leaving an empty procedure in its own category. What's more interesting, I think, is what makes the dialog fail, and by the time you have an XML to look at it's too late to explore that part.

No, it's perfectly valid.

The s attribute is the block spec, basically just a string representation of the block name, and where all it's inputs go.

<header> and <code> are used for codification, <translations> is used for language translations that you can put in blocks, and <inputs> defines all the inputs' info, such as type, default value, menu, etc.

Basically, that xml is 100% correct and not broken at all, the only thing that is broken, is snap somehow doing something with the constructor name (I know it's the object initialization method name in javascript, so that might be part of why it's breaking, though I don't know why it's doing this).

I made a Github issue for this, so eventually someone will do something about it. :~)

I think you are correct. I edited the XML of a broken project and changed the name of the block to something other than constructor, and my project was fixed and worked normally.

thanks! I've fixed this (and similar) cases for the next minor release.

i found that bug with toString in a block label

I found that any category with the name of a function/property will break the editor, for example this:

download

I don't have any blocks in them, and clicking on them ruins the IDE.

After reloading a project and trying to do things in dev mode just completely destructs the World.

And then nothing works properly.

Is this the way Earth will end? Not with a bang, but with a toString category (or an apostrophe in a block label)?

Let's see if it works in 10.1.2, i.e., if Jens's fix for block names also fixes the problem for category names. :~)

fixed just now for the upcoming patch. Thanks for the report!

i feel saif an saun on saulet graun