2
\$\begingroup\$

I wrote this up out of necessity, then realized that I actually needed to write it in PHP. Just so I didn't waste the last hour, I'd like a review of it. My concerns:

  1. This is my first time using the module pattern. Am I implementing it correctly?
  2. To restrict the creation of Either objects, I'm using Success and Failure as pseudo-axillary constructors to ensure that only one of Either's parameters is a meaningful value. Since they aren't real constructors though, they can't instantiate an Object, so I had to put the new inside of Success and Failure instead of expecting the caller to use it. Is this ok? Is there any way around it?
  3. Since I'm restricting the creation of Eithers, should I be checking the parameters, or just assume they're ok?
  4. Anything else. I've half moved on to writing PHP for the time being, but any suggestions on how to improve my JavaScript would be appreciated.

Example:

function someOperationReturningEither() {
    return Either.Success('Success');
}

someOperationReturningEither().then(
    function(successValue) {
        console.log('Succeeded!');
    },

    function(error) {
        console.log('Failure');
    }
);

var Either = (function() {
    /**
     * Represents either a value from a successful operation, or an error from one that failed
     * Only one of the paramters should be a valid value. The other must be null.
     *
     * @param {Object} succeeded The return of a successful operation, or null if failed
     * @param {Object} failed An object representing an error if the operation failed, or null if succeeded
     * @constructor
     */
    var Option = function(succeeded, failed) {
        var success = succeeded;
        var fail = failed;

        if (!hasValidState()) {
            throw invalidOptionStateError();
        }

        /**
         * Checks if the operation was successful
         *
         * @returns {boolean}
         */
        this.succeeded = function() {
            return succeeded !== null;
        };

        /**
         * Checks if the operation failed
         *
         * @returns {boolean}
         */
        this.failed = function() {
            return failed !== null;
        };

        /**
         * Calls the first callback if the operation was successful, otherwise the second callback is called
         * @param {SuccessCallback} onSuccess
         * @param {FailureCallback} onFail
         *
         * @returns {*} The return from the called callback
         */
        this.then = function(onSuccess, onFail) {
            if (this.succeeded()) {
                return onSuccess(success);

            } else if (this.failed()) {
                return onFail(fail);

            } else {
                throw new invalidOptionStateError();
            }


        };

        this.toString = function() {
            return "(" + success + ", " + fail + ")";
        };

        /**
         * Checks if only one of the options is given
         *
         * @returns {boolean}
         */
        function hasValidState() {
            return Boolean((success !== null) ^ (fail !== null));
        }

        /**
         * An Error reporting an invalid option state)
         * @returns {Error}
         */
        function invalidOptionStateError() {
            return new Error("Invalid Option state");
        }
    };

    return {
        /**
         * A wrapper over a successful value
         *
         * @param value The value to return
         * @returns {Option} An Option representing a successful operation
         */
        Success: function(value) {
            return new Option(value, null);
        },

        /**
         *
         * @param error An object representing a failed operation
         * @returns {Option}
         * @constructor
         */
        Failure: function(error) {
            return new Option(null, error);
        }
    };

    /**
     * @type SuccessCallback
     * @function
     *
     * @param {*} The return value of the operation
     * @returns {*}
     */

    /**
     * @type FailureCallback
     * @function
     *
     * @param {*} The error returned by the operation
     * @returns {*}
     */
})();
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.