SitePoint Sponsor

User Tag List

Results 1 to 20 of 20
  1. #1
    SitePoint Zealot
    Join Date
    Dec 2008
    Posts
    112
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    OO style JS - having issues with inheritance

    I've been trying to learn OO style JS today, but am having an issue with inheritance. I have the following, which seems to work okay, and is hopefully correct:
    Code:
    function Person(name){
        var job; //private
        this.name=name; //public
    }
        Person.prototype.setJob=function(jobb){
            job=jobb;
        }
        Person.prototype.getJob=function(){
            return job;
        }
        Person.prototype.getName=function(){
            return this.name;
        }
    
    function Postman(name){
        //construct the parent
        Person.call(this, name);
        //set the job on the parent
        //this.setJob('Postman');
        job="Postman";
    }
        //Postman extends Person
        Postman.prototype=new Person();
        Postman.prototype.parent=Person.prototype;
        //Postman constructor will be Person now, so switch it back to Postman
        Postman.prototype.constructor=Postman;
        
        //Override the parent method
        Postman.prototype.getName=function(){
            //call the parent method to get the name
            return this.getJob()+" "+this.parent.getName.call(this);
        };
    
    var MrsGoggins = new Person('Mrs Goggins');
    MrsGoggins.setJob('Shop assistant');
    console.log(MrsGoggins.getJob()); //Shop assistant
    console.log(MrsGoggins.getName()); //Mrs Goggins
    
    var Pat = new Postman('Pat');
    console.log(Pat.getJob()); //Postman
    console.log(Pat.getName()); //Postman Pat
    The issue is, if I modify the Person object so that name is required e.g.
    Code:
    function Person(name){
        var job; //private
        if(!name){
            throw {"name" : "InvalidArgument", "message" : "name of Person must be supplied", "toString" : function(){return this.name+": "+this.message}};
        }
        this.name=name; //public
    }
    Then when the script gets to Postman.prototype=new Person(); the error will be thrown as no name is supplied.

    So, I'm not sure how you are meant to extend an object if that object requires a parameter to be instantiated?

  2. #2
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by djeyewater View Post
    Then when the script gets to Postman.prototype=new Person(); the error will be thrown as no name is supplied.

    So, I'm not sure how you are meant to extend an object if that object requires a parameter to be instantiated?
    Yup, this was definitely a problem with JavaScript's inheritance model. Today, instead of using new Person() to extend the type, you would use Object.create.

    Postman.prototype = Object.create(Person.prototype);

    The caveat is that IE8 doesn't support Object.create, so if you still need IE8 support, then you'll have to monkey patch the global environment a bit.

    Code JavaScript:
    if (!Object.create) {
        Object.create = function (o) {
            function F() {}
            F.prototype = o;
            return new F();
        };
    }
    "First make it work. Then make it better."

  3. #3
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Also, take special care with your "private" variables. That only works if your code follows a specific pattern, where all your methods are defined and attached to each new instance within the constructor itself.

    Code JavaScript:
    function Person(name){
        var job; //private
        this.name=name; //public
     
        // define and attach methods to each new instance
        this.setJob=function(jobb){
            job=jobb;
        }
        this.getJob=function(){
            return job;
        }
        this.getName=function(){
            return this.name;
        }
    }
    "First make it work. Then make it better."

  4. #4
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Also also, JavaScript very sadly makes it extremely easy to make mistakes. A lot of the places where you referenced what you thought was a job instance variable, you were actually using a global variable. For example:

    Code JavaScript:
    var MrsGoggins = new Person('Mrs Goggins');
    MrsGoggins.setJob('Shop assistant');
     
    var Pat = new Postman('Pat');
     
    console.log(MrsGoggins.getJob()); // Oops. Postman?

    We should all consider it a requirement to check our code in JSHint. There are best practices we can adhere to that make JavaScript less error-prone, and JSHint will warn us if we miss one of those best practices anywhere in our code.
    "First make it work. Then make it better."

  5. #5
    SitePoint Zealot
    Join Date
    Dec 2008
    Posts
    112
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Thanks very much for the help and advice Jeff. I'm clearly not understanding the scoping issues, will have to play a bit more and read some more.

    Cheers

    Dave

  6. #6
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    @djeyewater ;

    In contrast to some other programming languages, it is perfectly legal in JavaScript to omit parameters even if the function has been defined to accept these arguments. The missing parameters are simply given the value undefined.

    So you got it all wrong. throw mechanism is what's getting in the way, no matter what, since it's "natural habitat' is inside a try..catch. Also, throwing string values, is rarely a good idea, because it makes it hard to recognize the type of the exception.

    Example 1
    Code:
    function Person(){
        var name = arguments[0];
        if(!name){
            throw {"name" : "InvalidArgument", "message" : "name of Person must be supplied", "toString" : function(){return this.name+": "+this.message}};
        }
        this.name=name; //public
    }
    
    try {
        var somebody = Person();
        console.log(somebody);
    } catch(e) {
        console.log("Why would you leave me nameless?!");
    }
    Example 2
    Code:
    function Person(){
        var name = arguments[0];
        if(!name){
            throw {"name" : "InvalidArgument", "message" : "name of Person must be supplied", "toString" : function(){return this.name+": "+this.message}};
        }
        this.name=name; //public
    }
    
    Person.prototype.setJob=function(jobb){
        job=jobb;
    }
    Person.prototype.getJob=function(){
        return job;
    }
    Person.prototype.getName=function(){
        return this.name;
    }
    
    function Postman(name){
        //construct the parent
        Person.call(this, name);
        //set the job on the parent
        //this.setJob('Postman');
        job="Postman";
    }
    
    try {
        //Postman extends Person
        Postman.prototype=new Person();
        Postman.prototype.parent=Person.prototype;
        //Postman constructor will be Person now, so switch it back to Postman
        Postman.prototype.constructor=Postman;
        
        //Override the parent method
        Postman.prototype.getName=function(){
            //call the parent method to get the name
            return this.getJob()+" "+this.parent.getName.call(this);
        };
    
    var MrsGoggins = new Person('Mrs Goggins');
    MrsGoggins.setJob('Shop assistant');
    console.log(MrsGoggins.getJob()); //Shop assistant
    console.log(MrsGoggins.getName()); //Mrs Goggins
    
    var Pat = new Postman('Pat');
    console.log(Pat.getJob()); //Postman
    console.log(Pat.getName()); //Postman Pat
    } catch(e) {
        console.log("My way or the highway");
    }
    Also, you got it wrong when you try to define constrains in the "class" constructor (object constructor really, you should drop any nostalgia from other languages and embrace the prototypal inheritance and terminology; while you're at it, renounce exception handling also, you know, throw, try..catch and such, there are better ways, better to learn how to catch Javascript ball). Instead, you simply put that constrain when creating new objects instead:
    Code:
    if (name) {
      var name = new Person(name);
    }

  7. #7
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    Also, you got it wrong when you try to define constrains in the "class" constructor...
    I think the community refers to this as one-stage vs two-stage construction. The OP is certainly welcome to try both approaches, but I don't think there's a consensus about which is the better approach. Personally, I can't think of a good reason why a JavaScript constructor shouldn't throw exceptions.

    http://stackoverflow.com/a/77705/1698612

    while you're at it, renounce exception handling also, you know, throw, try..catch and such
    Same deal. Could be worth exploring, but "renounce exception handling" is by no means standard practice in JavaScript.
    "First make it work. Then make it better."

  8. #8
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Personally, I can't think of a good reason why a JavaScript constructor shouldn't throw exceptions.
    Well, if an exception is thrown with object creation, and proper exception handling is in place (one important missing part which the OP doesn't have), normally the only code to be executed is an object deconstructor. This is the part where I mentioned the OP should embrace Javascript. Javascript is not C, so we don't do fine grain memory allocation control with it, we code smart, we don't get in the GC way and let GC do its work.

    Same deal. Could be worth exploring, but "renounce exception handling" is by no means standard practice in JavaScript.
    There is a use case for error handling by throw in Javascript, but it must be treated like an... exception! It must be something... exceptional! Otherwise, normal error handling is the norm: check for an error before doing the work or check and resolve on spot for error the returning result.

    The problem is not only with Javascript, but with "after the fact" error handling. Like I said, a throw must have a corresponding try..catch. But this means that an error will most likely occur only after some constructor and/or some other work has already began in this case.

    The main problem is understanding when to throw errors. And remember, the mission for the corresponding try..catch with objects is two step: first to deconstruct and then to handle errors in the most specific way possible, certainly not in a general manner.

    Doing it the clean way, like I did, keeping constraints outside the constructor, assures error handling on spot, before the fact, before entering or calling the constructor, before any work is done: if criteria is met then enter the constructor.

    Doing it like the OP did, putting the constrains inside the constructor results in a messy way of error handling, after some work has already been done: first entering or calling the constructor, then checking if criteria is met: throwing the error and then handling the error. The first two steps are memory consuming for nothing (why would you want to load the constructor before checking if you meet the criteria) and the last step is bound to make you forget to catch one thing or another.

  9. #9
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    Well, if an exception is thrown with object creation, and proper exception handling is in place (one important missing part which the OP doesn't have), normally the only code to be executed is an object deconstructor. This is the part where I mentioned the OP should embrace Javascript. Javascript is not C, so we don't do fine grain memory allocation control with it, we code smart, we don't get in the GC way and let GC do its work.
    Erm... I'm not sure why destructors and C became part of this conversation.

    Quote Originally Posted by myty View Post
    ...the mission for the corresponding try..catch with objects is two step: first to deconstruct and then to handle errors
    This is JavaScript. There is no "deconstruct" step. Are you perhaps coming from a C++ mindset?. Certainly in languages like C++, exception handling gets more tricky because you also have to free allocated memory.

    Quote Originally Posted by myty View Post
    Doing it the clean way, like I did, keeping constraints outside the constructor, assures error handling on spot, before the fact, before entering or calling the constructor, before any work is done: if criteria is met then enter the constructor.
    The downside is that there's no assurance of correctness. If the programmer has to do some error checking each and every time before invoking a constructor or any function for that matter, then eventually there will be a place in the code where the programmer forgot, or where the programmer didn't cover all the cases he was supposed to check for. If, on the other hand, the constructor checked its own arguments and threw an error as appropriate, then it would be pretty much impossible to construct an object and not perform these checks.

    Quote Originally Posted by myty View Post
    ...or check and resolve on spot for error the returning result.
    This kind of error handling gets extremely tedious for the programmer, to have to check the return value after every call to any function at every level of the call stack that might encounter an error. Plus it's harder to convey exactly what kind of error was encountered. Plus the function's valid return values might leave few choices for an "error" return value.

    Code JavaScript:
    var result = doSomething();
    if (result === null) {
        // does null mean "no value" or does it mean "error"?
        // if it's an error, then why exactly did it fail?
        // if this is an error that can't or shouldn't be handled at this level
        // then all I can do is pass the error further up the call stack
        return null;
    }

    By contrast, when exceptions are used, programmers don't have to explicitly check every return value. They can try/catch a whole block of code at once. Or they can allow the exception to cascade up the call stack where certain kinds of errors are more properly handled. Plus exceptions can specify exactly what kind of error occurred with a detailed message. Plus there is zero overlap between valid return values and errors.

    Quote Originally Posted by myty View Post
    ...first entering or calling the constructor, then checking if criteria is met: throwing the error and then handling the error. The first two steps are memory consuming for nothing (why would you want to load the constructor before checking if you meet the criteria) and the last step is bound to make you forget to catch one thing or another.
    Worrying about the memory consumption of entering a function before throwing an error sounds like a micro-optimization to me. And although, yes, the programmer might forget to catch an exception, the worse alternative is that the programmer might forget to check for an error condition entirely.
    "First make it work. Then make it better."

  10. #10
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Though I do want to add that this is not a clear-cut issue. Some very smart people have tried and continue to try going exceptionless. Google's C++ style guide reads like a back-and-forth debate. They start off saying they don't use exceptions. Then they give a nice pro/con list. Then they say, "Things would probably be different if we had to do it all over again from scratch." And that, "On their face, the benefits of using exceptions outweigh the costs, especially in new projects."

    On the other hand, Google's Go programming language was designed to be exceptionless.

    On the other other hand, Google's JavaScript style guide says yes, use exceptions.

    It's certainly an interesting idea that's worth exploring, but for people who are still learning, like the OP, I think we should avoid saying that there is a definite right or wrong choice (because there isn't), and I think we should avoid saying that exceptionless is standard practice in JavaScript (because it isn't).
    "First make it work. Then make it better."

  11. #11
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    I said exceptions have their place in Javascript, just not in the constructor.

    Quote Originally Posted by myty View Post
    There is a use case for error handling by throw in Javascript, but it must be treated like an... exception! It must be something... exceptional! Otherwise, normal error handling is the norm: check for an error before doing the work or check and resolve on spot for error the returning result.
    For an example where I would use exceptions, see this thread: http://www.sitepoint.com/forums/show...=1#post5577834

  12. #12
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    ...just not in the constructor.
    And why, exactly? (When you tried to explain this before, you ended up talking about destructors and C.)
    "First make it work. Then make it better."

  13. #13
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    I *have* explained it before, you just didn't try to understand.

    Because that's the pattern in other languages for using exceptions with object constructors: if an exception occurs, the only thing to do is to free the memory up from whatever leftover the constructor started generating.

    In Javascript this doesn't apply, you don't usually clean up memory, even if it can be done. You let the GC work.

    And it's also simpler, smarter, cleaner to just check for new object criteria before calling the constructor.

  14. #14
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    Because that's the pattern in other languages for using exceptions with object constructors
    Weren't you saying earlier that JavaScript is not C, and we should embrace JavaScript? It doesn't matter what other languages do.

    Quote Originally Posted by myty View Post
    In Javascript this doesn't apply
    Thank you. That's kinda my point. In C++, there may be a good reason to avoid exceptions in the constructor, but in JavaScript, it's not a problem.
    "First make it work. Then make it better."

  15. #15
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    What can I say. You got it backwards. You misconstrue. Have it your way.

  16. #16
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    @Jeff Mott ;

    Maybe this is doing a better job to convince you throwing errors should be used sparsely in Javascript, and support my claim about well known issues when throwing errors: http://flippinawesome.org/2013/09/30...ipts-trycatch/

    It is such a powerful construct that in a perfect world you would want to wrap everything in a try/catch block to provide simple and effective error trapping. However, due to concerns in performance critical situations, employing it is often frowned upon in JavaScript.

    [...]

    No matter what context you use a try/catch block in, there will always be an inherent performance hit, quite possibly a substantial one.
    I'd expect if you choose to carry on antagonistically to at least post some legitimate sources as well.

  17. #17
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    I'd expect if you choose to carry on antagonistically to at least post some legitimate sources as well.
    Before you get too snarky, you should at least realize that the article you linked to makes a completely different argument with completely different reasoning than what you were saying. Your arguments were "renounce exception handling," and "you got it wrong when you try to define constrains in the 'class' constructor."

    In contrast, the article you linked to doesn't say anything about when you should or shouldn't throw. It's whole premise is to offer a custom try/catch construct that's supposed to deliver better performance. It still expects you to throw exceptions in the normal way.

    EDIT: And to boot, their's is a micro-optimization. They say "90% loss in performance," but they don't say what that actual time is. Turns out that 90% is equal to four nanoseconds (that is, four one-thousandths of a microsecond).
    "First make it work. Then make it better."

  18. #18
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Man, are you that thick? What did you expect the article to say: "Yes Jeff, myty is right!"? And yes, they're making the same argument: use error throwing sparsely. It's an art, error throwing, and so beginners should just stay off it. If "employing it is often frowned upon in JavaScript" doesn't convince you, what does?

    Just please stop with the act and please link back with something substantial and legitimate! Link to at least a quasiknown piece of software that uses throws in the constructors or error throwing extensively. OK?

    Here it is, one more: http://stackoverflow.com/questions/3...-checking-code

    Avoid try-catch in performance-critical functions, and loops
    [...]
    Use them wisely, use them sparingly.
    [...]
    But as I see you clearly misuse some functions for error checking. You can test for the desired objects and properties of objects right before you use them instead of complex checking.
    And before you again say they're saying something different:
    Quote Originally Posted by myty View Post
    And it's also simpler, smarter, cleaner to just check for new object criteria before calling the constructor.
    Here's another: http://developer.nokia.com/Community...Best_Practices
    Or if possible, avoid try-catch-finally completely

  19. #19
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Here's another: http://programmers.stackexchange.com...-good-practice
    One should avoid throw errors as the way to pass error conditions around in applications.
    The throw statement should only be used "For this should never happen, crash and burn. Do not recover elegantly in any way"
    try catch however is used in situation where host objects or ECMAScript may throw errors.
    [...]
    There are also other issues like try / catch is really expensive and it's ugly and it simply doesn't work with asynchronous operations.

    So since synchronous operations should not throw an error and it doesn't work with asynchronous operations, no-one uses try catch except for errors thrown by host objects or ECMAScript
    and in comments:
    I wouldn't go so far as to say no one uses try catch, it's just the wrong tool for the job in most cases. When there are truly exceptional circumstances, it can be worthwhile to throw an Error, but they are few and far between.
    and yes, they're agreeing with me:
    Quote Originally Posted by myty View Post
    There is a use case for error handling by throw in Javascript, but it must be treated like an... exception! It must be something... exceptional! Otherwise, normal error handling is the norm: check for an error before doing the work or check and resolve on spot for error the returning result.
    Now, please get a little snarky in return and post something better. I am in favor of changing my programming habits even if it's a 180, but let it be something serious.

  20. #20
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    Man, are you that thick? What did you expect the article to say: "Yes Jeff, myty is right!"?
    I expected it to back up the points you were trying to make. It didn't.

    Quote Originally Posted by myty View Post
    And yes, they're making the same argument: use error throwing sparsely.
    See, the thing is, this claim is extremely easy for anyone to check. The article you linked to definitely said no such thing. The word "throw" is only even used just once. Here's the sentence: "The event is capable of detecting runtime errors including any errors that you explicitly throw yourself." It says absolutely nothing about when you should or shouldn't throw.

    Quote Originally Posted by myty View Post
    Just please stop with the act and please link back with something substantial and legitimate!
    Such as, perhaps, Google style guides? Look above. I already did that. Or if you like StackOverflow, then look above, I linked to a SO answer as well.

    Quote Originally Posted by myty View Post
    Couple things here. 1) The answer is talking about the performance of try/catch. Not about throwing in a constructor, or even about throwing in general. And 2) Look at the SO answer I linked to above. Which, by the way, is exactly on topic. It's about whether it's OK to throw from a constructor. The top voted answer says, "I've never understood the reasoning behind this approach. I'm firmly in the group that supports one-stage construction."

    And just to reiterate, I never said that it's absolutely right to throw from the constructor. You told the OP that he was absolutely wrong, and my rebut was, "I don't think there's a consensus about which is the better approach." That seems to me to be a calm and reasonable and accurate rebut. So... chill.

    Quote Originally Posted by myty View Post
    This says the same thing as all your other links: "Don't use try-catch-finally inside performance-critical functions." And if your argument was to avoid exceptions in performance critical places, then I would certainly agree with you. But that wasn't your argument, nor is it what I've been rebutting all this time. Your argument was about whether it's OK to throw from a constructor, and whether we should "renounce exception handling" in general, regardless if it's performance critical or not. None of your links have backed up that argument.

    Quote Originally Posted by myty View Post
    Finally, for the first time, a link that supports (part) of your argument. So what we have now is a SO answer that says one thing, and a SE answer that says another. Pretty sure this backs up my statement that there's no consensus. If we can agree on at least that much, then we can start a new thread and discuss the pros and cons of exception handling, and hopefully we'll both come out of it knowing something that we didn't before.
    "First make it work. Then make it better."


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •