constructor() {
        /** @type {!string} The text shown when drawing the gate. */
        this.symbol = '';
        /** @type {!string} The identifier text used for the gate when serializing/parsing JSON. */
        this.serializedId = '';
        /** @type {!string} The title text of gate tooltips. */
        this.name = '';
        /** @type {!string} Detail text of gate tooltips. */
        this.blurb = '';
        /** @type {!int} The number of columns the gate spans on a circuit. Controls go on the first column. */
        this.width = 1;
        /** @type {!int} The number of wires the gate spans on a circuit. */
        this.height = 1;
        /** @type {undefined|!string|!number|!Array} A custom value that gets serialized.
         *     Each gate may use it to determine behavior. */
        this.param = undefined;
        /**
         * Updates gate properties based on a new parameter value.
         * Called by `Gate.withParam` before returning its result.
         * @type {!function(gate: !Gate): undefined}
         * @private
         */
        this._withParamRecomputeFunc = g => {};

        /** @type {undefined|!function(!GateDrawParams) : void} Draws the gate. A default is used when undefined. */
        this.customDrawer = undefined;
        /** @type{undefined|!function(!Gate) : !Gate} */
        this.onClickGateFunc = undefined;
        /** @type {undefined|*} Used to stash error information when parsing goes bad. */
        this.tag = undefined;
        /**
         * An operation applied during the 'setup' phase of computing a column.
         * NOT AFFECTED BY CONTROLS.
         * @type {undefined|!function(!CircuitEvalContext) : void}
         */
        this.customBeforeOperation = undefined;
        /**
         * An operation applied during the main phase of computing a column.
         * @type {undefined|!function(!CircuitEvalContext) : void}
         */
        this.customOperation = undefined;
        /**
         * An operation applied during the 'cleanup' phase of computing a column.
         * Usually the inverse of the before operation.
         * NOT AFFECTED BY CONTROLS.
         * @type {undefined|!function(!CircuitEvalContext) : void}
         */
        this.customAfterOperation = undefined;
        /**
         * Produces a texture containing information that can be used by the drawing code of display gates.
         * @type {undefined|!function(!CircuitEvalContext) : !WglTexture|!Array.<!WglTexture>}
         */
        this.customStatTexturesMaker = undefined;
        /**
         * Returns some more useful form of the pixel data read from the custom-stat texture.
         * @type {undefined|!function(!Float32Array, !CircuitDefinition, !int, !int) : *}
         */
        this.customStatPostProcesser = undefined;
        /**
         * Returns a json form of the custom-stat data, used when exporting it.
         * @type {undefined|!function(data: *) : *}
         */
        this.processedStatsToJsonFunc = undefined;
        /** @type {!Array.<!Gate>} A list of size variants of this gate.*/
        this.gateFamily = [this];

        /** @type {!boolean} Determines if vertical lines are drawn between this gate and controls. */
        this.interestedInControls = true;
        /**
         * Determines if circuits containing this gate need to actively animate.
         * @type {undefined|Infinity|!number}
         * @private
         */
        this._stableDuration = undefined;
        /**
         * Determines the gate's operation (if no shader is specified).
         * @type {undefined|!Matrix}
         * @private
         */
        this._knownMatrix = undefined;
        /**
         * Determines the gate's time-varying operation (if no shader is specified).
         * @type {undefined|!function(time: !number) : !Matrix}
         * @private
         */
        this._knownMatrixFunc = undefined;
        /**
         * Indicates whether the gate can just be skipped over when computing.
         * @type {!boolean}
         * @private
         */
        this._hasNoEffect = false;
        /**
         * Indicates whether the gate's effect is classical, and so can apply to measured bits but perhaps not
         * combinations of measured and unmeasured bits.
         * @type {undefined|!boolean}
         * @private
         */
        this._effectPermutesStates = undefined;
        /**
         * Indicates whether the gate's effect is inherent quantum (w.r.t. the Z basis), and so is not safe to apply
         * to measured bits.
         * @type {undefined|!boolean}
         * @private
         */
        this._effectCreatesSuperpositions = undefined;
        /**
         * Indicates whether vertical lines should be drawn from this gate to gate's marked as controllable.
         * @type {!boolean}
         */
        this.isControlWireSource = false;
        /**
         * A circuit that is equivalent to this gate.
         * If no shader or matrix is specified, the circuit will be recursed into to compute the gate.
         * @type {undefined|!CircuitDefinition}
         */
        this.knownCircuit = undefined;
        /**
         * A cached version of the circuit equivalent to this gate, with slightly looser disabled reasons, used when
         * drawing tooltips.
         * @type {undefined|!CircuitDefinition}
         */
        this.knownCircuitNested = undefined;
        /**
         * Indicates context (such as 'Input Range A') that must be provided by other gates in the same column, or
         * earlier in the circuit in some cases, in order for this gate to function.
         * Doesn't include keys inherited from the gate's circuit (if known).
         * @type {!Array.<!string>}
         */
        this._requiredContextKeys = [];
        /**
         * Indicates whether the simulator needs to compute a qubit density matrix at locations/times where this gate is
         * placed.
         * @type {!boolean}
         */
        this.isSingleQubitDisplay = false;

        /**
         * Determines if this gate conditions or anti-conditions other operations or not.
         * Note that 'False' means 'anti-control', not 'not a control'. Use undefined for 'not a control'. Also,
         * this value may be set to "parity" to indicate a parity control.
         * Non-computational-basis controls also use this mechanism, but with before/after operations.
         * @type {undefined|!string|!boolean}
         * @private
         */
        this._controlBit = undefined;
        /**
         * Determines if a controlled gate's control is guaranteed to be known classically. This is used by the
         * combination detect-control-reset gates as a way to communicate that they can control permutation operations
         * on classical wires.
         * @type {boolean}
         * @private
         */
        this._isClassicalControl = false;
        /**
         * Indicates that this gate is guaranteed to preserve probability (as opposed to e.g. post-selection).
         * When gates with this property not set to true are present in a column, the simulator computes losses/gains.
         * @type {!boolean}
         * @private
         */
        this._isDefinitelyUnitary = false;
        /**
         * The alternate gate for this one, used when shift+alt dragging.
         * @type {!Gate}
         */
        this.alternate = this;
        /**
         * Returns context provided by this gate to other gates in the same column (or later columns in some cases).
         * @param {!int} qubit
         * @param {!Gate} gate
         * @returns {!Array.<!{key: !string, val: *}>}
         */
        this.customColumnContextProvider = (qubit, gate) => [];
        /** @type {!boolean} Determines if context generated by this gate sticks around for later columns or not. */
        this.isContextTemporary = true;
        /**
         * Checks for non-standard reasons that a gate should be disabled (e.g. modulus too big to fit in target).
         * @param {!GateCheckArgs} args
         * @returns {undefined|!string}
         */
        this.customDisableReasonFinder = args => undefined;
        /**
         * Indicates that a gate is a re-arrangement of the wires equivalent to the given function.
         * @type {undefined | !function(!int) : !int}
         */
        this.knownBitPermutationFunc = undefined;
        /**
         * When a permutation factors into sub-permutations over subsets of the bits, this map indexes each bit with
         * an id for the group that it belongs to.
         * @type {!Array.<!int>}
         */
        this.knownBitPermutationGroupMasks = undefined;
        /**
         * Indicates that a gate is a phasing function, and that it phases each computation basis state by the amount
         * returned by this function.
         * @type {undefined | !function(state: !int) : !number}
         */
        this.knownPhaseTurnsFunc = undefined;
        /**
         * Indicates that a gate is a re-arrangement of the basis states equivalent to the given function.
         * Used by all-gate tests to check that shaders are behaving correctly.
         * @type {
         *      !function(val: !int) : !int |
         *      !function(val: !int, a: !int) : !int |
         *      !function(val: !int, a: !int, b: !int) : !int |
         *      !function(val: !int, inputs: ...!int) : !int
         *  }
         */
        this.knownPermutationFuncTakingInputs = undefined;

        /**
         * Indicates that this gate should be shown as if it was not localized to the wires it is placed on, even if
         * this gate has no direct effect on the state vector.
         *
         * Example: used by SetInput gates, which technically have no effect but do change gates on far away wires.
         *
         * @type {boolean}
         * @private
         */
        this._showAsReachesOtherWires = false;
    }
Describes a quantum operation that may vary with time.