Generally speaking, in the JS world at least, if you're passing more than a few parameters into a function you might have code complexity problems. If you need to pass in a bunch of data to a function you tend to do it in a single options object with some runtime checking to work out what to do with it. Any remaining problems should be caught with good test coverage. Being able to flexibly and clearly handle variable numbers of function arguments without getting entangled in an involved function overloading syntax and methodology is actually sometimes pretty nice. It's a feature not a problem. Haha :P
>>How do you handle Javascript ignoring wrong numbers of function arguments?
>if you're passing more than a few parameters into a function
I didn't know you had to have "more than a few parameters" before you could make a coding error related to the number of parameters you pass something.
It's just never been a problem for me, I guess? I know how it works in JS, so I either ignore it or use it to my advantage (the JS equivalent of overloading). You seem to come from a more strongly-typed background, but I've never once found the way JS handles it to be "catastrophic".
How do you ignore it? Ignoring it means accepting cryptic bugs that result from signature changes.
You say "use to your advantage", but what's the advantage? You could have a "*args" like Python, and get the benefits without the (huge) drawback.
The typing debate is mostly about how much effort we should exert to catch errors at compile time rather than run time. In JS, it is much worse: It defers error catching forever, and never even catches them at all! It converts them to silent bugs, instead :(
Is this so much of a problem that we need to re-design JS to handle it? Why not just avoid making this mistake in the first place by reading the code? Not to sound dismissive - but if you're making these kinds of mistakes regularly enough to irritate you, it's not the language that's at fault.
Javascript's squishiness is the thing I like the most about it. It's far from perfect, just like any other language out there - but it's fun.
> Why not just avoid making this mistake in the first place by reading the code?
We're talking about programming errors. Are you suggesting the solution to human error is to just not make errors??
Note, of course, that wrong arguments will frequently not arise from a function call you just wrote -- but from changes in the code.
Say you merge in a trivial merge of some code, which changed a function's signature/parameters. The merge succeeds trivially. Now every single function call is a bug that is not only uncaught by a compiler. It won't even necessarily be caught at runtime. Instead, it may escalate to catastrophic, undefined/unexpected behavior.
> We're talking about programming errors. Are you suggesting the solution to human error is to just not make errors??
Not at all, I'm simply suggesting that people take care to acknowledge and operate within the rules of the language. If you're making changes to a function signature in JS without assessing the impact for code elsewhere, then you're doing a bad job - and that's all there is to it. JS allows you to do something which when ignored or fucked up, results in problems. This is not a JSism - this is just the way things work. Every language has 'features' like this. If you don't know what you're doing, then stop doing it. "A bad workman blames his tools" and all that jazz.
> Note, of course, that wrong arguments will frequently not arise from a function call you just wrote -- but from changes in the code.
So JS has a (potentially) higher maintenance cost. This doesn't mean that JS is badly designed - it's just a trade-off. Some people don't care, others do. Clearly to some people, it's an unacceptable cost - but all that means is that those people have a lower tolerance for that kind of thing than others.
> Say you merge in a trivial merge of some code, which changed a function's signature/parameters. The merge succeeds trivially. Now every single function call is a bug that is not only uncaught by a compiler. It won't even necessarily be caught at runtime. Instead, it may escalate to catastrophic, undefined/unexpected behavior.
This is just a case for good documentation and release notes. Don't merge in changes that you don't understand.
> If you're making changes to a function signature in JS without assessing the impact for code elsewhere, then you're doing a bad job - and that's all there is to it.
Given that other people are working on the same code base and may have added calls to this function, this is not even possible.
Also, dynamic languages all require you to fix calls to changed functions. But at least, when you test that code, it won't accidentally seem to work when it is broken.
Also, humans cannot do a perfect job every time. We will all make mistakes, and our tools shouldn't give us hell over those mistakes for miniscule to no benefit at all as in this case.
Out of thousands of changes to function signatures, do you think none would ever forget to fix a caller?
> So JS has a (potentially) higher maintenance cost
This doesn't sound potential at all. It sounds like you either lose a huge amount of reliability, or add a huge burden to development.
> it's just a trade-off
What do you gain here? You save an asterisk in the syntax when you want to overload?
> This is just a case for good documentation and release notes. Don't merge in changes that you don't understand.
In a collaborative environment, we merge work with each other every single day. Do you have documentation and release notes for every commit you publish? Do you go and check the commit's release notes every time you pull?
> Given that other people are working on the same code base and may have added calls to this function, this is not even possible.
Except it clearly is possible since I and millions of other developers seem to manage it daily.
> Also, dynamic languages all require you to fix calls to changed functions. But at least, when you test that code, it won't accidentally seem to work when it is broken.
This is a problem of your code-base, not the language. If your code is so brittle that it can't stand a few function changes without collapsing into a miasma of shit, then whose fault is that? Of course you need to fix calls to changed functions - but if doing so is causing you and your team pain, then perhaps you have other problems.
> This doesn't sound potential at all. It sounds like you either lose a huge amount of reliability, or add a huge burden to development.
Of course it's potential. Nobody's forcing you to write tightly coupled, shitty code which breaks after every merge. Seriously? Figure it out.
> What do you gain here? You save an asterisk in the syntax when you want to overload?
Like I said before, squishiness.
> In a collaborative environment, we merge work with each other every single day.
As do I, and clearly millions of other developers who don't seem to run into your problems.
> Do you have documentation and release notes for every commit you publish?
We have proper commit messages and tracking codes for every task / bug, yes. There's no such thing as perfect information - and sometimes merges get messy - but this is not unique to JS. Sure, not every single commit is perfectly documented, but small commits and concise messages go a long way to ensuring that the history is traceable and the code is clean. The more often you commit and merge with your collaborators, the more in lock-step you are and the less likely you are to run into these kinds of issues. Messy merges will happen from time to time regardless of your preferred language.
> Do you go and check the commit's release notes every time you pull?
Not always, but often. Maintaining visibility of the trajectory of the code and the project as a whole will help massively in heading off risks and development issues.
> Except it clearly is possible since I and millions of other developers seem to manage it daily.
Clearly possible to fix code that's in branches/working trees that you don't even have access to??
> This is a problem of your code-base, not the language. If your code is so brittle that it can't stand a few function changes without collapsing into a miasma of shit
When you change function signatures, code that calls those functions is broken. In static languages the breakage is a compile-time error. In dynamic languages the breakage is a run-time error. In JS the breakage is a cryptic bug.
> Of course it's potential. Nobody's forcing you to write tightly coupled, shitty code which breaks after every merge. Seriously? Figure it out.
The code is tightly-coupled and shitty because it has functions that get called?
> Like I said before, squishiness.
By squishiness, do you mean "trade errors for cryptic bugs"? You seem to be exactly who Dijkstra referred to when he said [1]:
> It was a significant improvement that now many a silly mistake did result in an error message instead of in an erroneous answer. (And even this improvement wasn't universally appreciated: some people found error messages they couldn't ignore more annoying than wrong results, and, when judging the relative merits of programming languages, some still seem to equate "the ease of programming" with the ease of making undetected mistakes.)
> As do I, and clearly millions of other developers who don't seem to run into your problems.
I'm wise enough to avoid JS, so I don't encounter such silly problems. I don't trust you to even know you are having these troubles, because the whole point is that these problems translate to cryptic bugs, rather than visible errors.
> We have proper commit messages and tracking codes for every task / bug, yes. There's no such thing as perfect information - and sometimes merges get messy - but this is not unique to JS
Note that the word "merges" may be misleading here. As every little pull you do (even a FF pull in git which updates files that don't overlap with your modified files) is a merge for this purpose.
Your approach here means that I must review all the function signature changes in every commit I pull, synchronously, before I carry on work. This doesn't help lock-step development as it incurs a serious overhead on such development.
> Not always, but often
That means when you pull, all the function calls to functions that may have had their signatures changed in your pulls may now become cryptic bugs. Awesome!
> Clearly possible to fix code that's in branches/working trees that you don't even have access to??
This is a non-issue - if you're using unstable libraries then that's your own problem and breakages are to be expected. This is not the fault of JS.
> When you change function signatures, code that calls those functions is broken. In static languages the breakage is a compile-time error. In dynamic languages the breakage is a run-time error. In JS the breakage is a cryptic bug.
When you change function signatures, you document the change and you increment the version. If you're randomly updating dependencies without first checking that the new version is compatible with your existing code, then that's your problem. Again, this is not JS.
> The code is tightly-coupled and shitty because it has functions that get called?
If a change in a dependency causes you to have a ripple effect of completely broken code - then yes, your code is tightly coupled.
> By squishiness, do you mean "trade errors for cryptic bugs"? You seem to be exactly who Dijkstra referred to when he said [1]:
Squishiness is difficult to explain without describing the general ins and outs of dynamic languages, which I'm sure you're not completely alien to. Essentially, what I'm saying is that the problems you're experiencing with JS are largely your own fault - and no amount of complaining is going to solve the problem of the user lacking due diligence when they rely on unstable code or aren't maintaining their own dependent code properly. Again, these problems are not specific to JS.
> I'm wise enough to avoid JS, so I don't encounter such silly problems.
So you're weighing in on the problems of a language you don't even use. Doesn't that strike you as somewhat...silly?
> I don't trust you to even know you are having these troubles, because the whole point is that these problems translate to cryptic bugs, rather than visible errors.
They translate to cryptic bugs if you develop shitty software, sure. However, if you do your homework, correctly check your dependencies and retain some semblance of stability in your code-base, then no, these problems aren't nearly as dramatic as you're suggesting.
> Note that the word "merges" may be misleading here. As every little pull you do (even a FF pull in git which updates files that don't overlap with your modified files) is a merge for this purpose.
A merge is a merge is a merge. If you're merging unstable code, then you have to expect that you're going to need to do some maintenance. In what world is it sensible to develop software where you're not even attempting to ensure that potentially breaking changes aren't flagged up, discussed, and dealt with? Have you never heard of the phrase 'don't break the build'? In my job, if somebody commits and pushes something which is going to completely fuck the rest of the development team, then they're told to piss off and fix it. If you absolutely must change a function signature which is part of an API that others may be depending on, then you fucking document it and alert your users. Again, not JS. Sort your process out.
> Your approach here means that I must review all the function signature changes in every commit I pull, synchronously, before I carry on work. This doesn't help lock-step development as it incurs a serious overhead on such development.
No, my approach is that if I'm developing a library which others depend on, I don't fuck about with the API without a very, very good reason - and if I do, then I document it. Don't randomly update your dependencies if this is such a problem for you. If your code is so tightly coupled to whatever dependencies you have that updating that dependency means you need to change a thousand different lines of code scattered throughout your software, then you're already doing it wrong.
> That means when you pull, all the function calls to functions that may have had their signatures changed in your pulls may now become cryptic bugs. Awesome!
Except it doesn't, because who updates a dependency without checking that they can actually depend on it? The clue's in the name.
It seems you are misunderstanding me. I am not talking about library APIs here. I am talking about internal function signatures inside a single product developed by multiple codevelopers.
All your replies about external APIs changing are irrelevant. A codeveloper touching functions that call your functions or defining functions called by you will integrate with your work with an innocuous "git pull" and force you to review everything just to rule out what JS could have easily detected.
> If a change in a dependency causes you to have a ripple effect of completely broken code - then yes, your code is tightly coupled.
Again, I'm not talking about "dependencies" or libraries here at all.
> In my job, if somebody commits and pushes something which is going to completely fuck the rest of the development team, then they're told to piss off and fix it.
The push was completely benign. The integration of that push with your current work will be broken in cryptic ways. Not necessarily ones that show up in the testing suites.
> If you absolutely must change a function signature which is part of an API that others may be depending on, then you fucking document it and alert your users. Again, not JS. Sort your process out.
Every single function signature can break things, not just exposed APIs. Two developers might work on the same piece of code. There's not necessarily any obvious point to notify here and still breakage may arise.
> Except it doesn't, because who updates a dependency without checking that they can actually depend on it? The clue's in the name.
You clearly haven't understood the scenario involved, I'll try to describe it again:
1) Developer A adds a new function FOO that calls internal function BAR in his unpushed working tree.
2) Developer B changes the signature of internal function BAR, and pushes this change to "master".
3) Developer A pulls from master, his code is now broken, but JS doesn't even warn him when he executes it. Instead, wrong results (or accidentally correct results for any given test case) arise.
4) The test suites don't catch the error. Developer A unwittingly pushes the broken code to master.
> All your replies about external APIs changing are irrelevant. A codeveloper touching functions that call your functions or defining functions called by you will integrate with your work with an innocuous "git pull" and force you to review everything just to rule out what JS could have easily detected.
Everything that you didn't write yourself is an external API for all intents and purposes - you're using somebody else's code, regardless of whether that person 'owns' the code or not. The fact remains that if you're relying on a function and somebody changes it without considering the consequences, then that's a process issue, not a JS one. In the same way, if you're writing code which others may depend on, then you need to consider the potential consequences of your changes.
> Again, I'm not talking about "dependencies" or libraries here at all.
The point is that you should be talking about dependencies and libraries. The situation you're describing is one in which code is not properly modularised and organised - where any developer can change any function and thereby fuck up the rest of the project. If your code was organised properly, these problems would disappear.
> The push was completely benign. The integration of that push with your current work will be broken in cryptic ways. Not necessarily ones that show up in the testing suites.
You keep using the word 'will'. I'm telling you with hand on heart that this problem does not happen if you sort out your development team and project structure.
> Every single function signature can break things, not just exposed APIs.
Yes, it can break things, but it shouldn't.
> Two developers might work on the same piece of code. There's not necessarily any obvious point to notify here and still breakage may arise.
If two developers can't work on the same area of code without stepping all over each other, then you need to look at how you're structuring your code.
> 1) Developer A adds a new function FOO that calls internal function BAR in his unpushed working tree.
> 2) Developer B changes the signature of internal function BAR, and pushes this change to "master".
> 3) Developer A pulls from master, his code is now broken, but JS doesn't even warn him when he executes it. Instead, wrong results (or accidentally correct results for any given test case) arise.
> 4) The test suites don't catch the error. Developer A unwittingly pushes the broken code to master.
Why is developer B changing the signature of function BAR willy nilly? Code isn't written in isolation and your changes have an effect on other developers. If you have a function which is being used by other people - then you have a public API. You don't break an API randomly.
So basically you need to use strict ownership at API boundaries as that is the only way to avoid this. This isn't always optimal. It sounds like you're sacrificing quite a few goats at the js altar for no real benefit.
Your question about why a developer would need to change an internal function's signature is ridiculous. Maintaining code involves changing function signatures all the time. If another developer is working within the same API boundary, he's screwed.
This isn't a necessary fact of life. Even most sane dynamic language will error out when such incompatibility arises, instead of blaming the developer for using a process incompatible with the js way.
Not to mention the other argument, that with all the discipline in the world, humans will still make mistakes. Instead of translating to errors, they translate to bugs.
The gain? not having to use an asterisk when you want varargs. That's just stupid.
> So basically you need to use strict ownership at API boundaries as that is the only way to avoid this. This isn't always optimal. It sounds like you're sacrificing quite a few goats at the js altar for no real benefit.
No, but when somebody I'm working with makes a potentially breaking change to a shared codebase, they either ensure that they also fix the now broken code, or they flag it up to the people whose responsibility that is. Aside from that - most people simply avoid making a breaking change - or if it absolutely must be made, then a process is followed.
> Your question about why a developer would need to change an internal function's signature is ridiculous
I wasn't asking why the developer was changing a function signature - rather why they're so eager to change a function signature without following up and either fixing the things they break, or flagging those things up to the people who require it.
> This isn't a necessary fact of life. Even most sane dynamic language will error out when such incompatibility arises, instead of blaming the developer for using a process incompatible with the js way.
There's no such thing as a random error. If there's an error, somebody made a mistake. Some mistakes are stupid, others are subtle. Changing a method signature and then not doing something about the callers is a stupid mistake.
> Not to mention the other argument, that with all the discipline in the world, humans will still make mistakes. Instead of translating to errors, they translate to bugs.
Of course humans will make errors - but your job is to minimise the frequency and severity of those errors. There's no excuse for sloppiness - you either keep on top of shit, or you don't. Call it whatever you like, but a shitty broken codebase is only the fault of the developers, not the language.
> Aside from that - most people simply avoid making a breaking change - or if it absolutely must be made, then a process is followed.
Changing internal functions is not considered a "breaking change" by anyone I know. You're allowed to refactor code internally, which definitely includes changing the structure of the internal functions.
Other coders who are also working inside the same module/API boundary will have their edits broken by this change. The original developer cannot fix their code because it's not checked in yet.
> rather why they're so eager to change a function signature without following up and either fixing the things they break, or flagging those things up to the people who require it.
I already explained why they can't follow up - because the code that needs the follow up is in their codevelopers' working trees. Flagging here would be silly. Almost every single commit would be "flagged for fixing breakage", since every single commit can refactor/change internal function signatures.
> If there's an error, somebody made a mistake. Some mistakes are stupid, others are subtle. Changing a method signature and then not doing something about the callers is a stupid mistake.
Yes, and we are all human so sometimes, despite heroic efforts, we will all make stupid mistakes as well as subtle mistakes.
Now, once we made the mistake, do we want our tool to insidiously hide this mistake from us, making it as expensive as possible to punish us for our mistake? Or do we want a tool that tells me ASAP "Hey dude, you made a stupid mistake over there"?
> but your job is to minimise the frequency and severity of those errors.
And to do this job, I have tools like languages that help me find those mistakes quickly.
> There's no excuse for sloppiness
Making mistakes isn't "sloppiness", it's human.
> Call it whatever you like, but a shitty broken codebase is only the fault of the developers, not the language
If one language makes writing a non-shitty codebase harder than a different language, it is also the fault of that language.
> Changing internal functions is not considered a "breaking change" by anyone I know.
If changing internal functions results in breakages, then I don't know what else you'd call it except a breaking change.
> You're allowed to refactor code internally, which definitely includes changing the structure of the internal functions.
If the person changing the function doesn't then go and update all of the callers, then that person isn't doing their job properly. It's not refactoring if you just randomly decide to modify a single function's signature and then don't follow up and fix the rest of the code.
> Other coders who are also working inside the same module/API boundary will have their edits broken by this change. The original developer cannot fix their code because it's not checked in yet.
Not if you're making small commits, often. Changing a function signature necessitates the modification of all callers to that function. This would be a large commit which includes all of necessary changes to ensure that the software remains in a stable state.
> I already explained why they can't follow up - because the code that needs the follow up is in their codevelopers' working trees. Flagging here would be silly. Almost every single commit would be "flagged for fixing breakage", since every single commit can refactor/change internal function signatures.
This is still just a process problem - if you committed and merged more often, these issues wouldn't arise. The reason you're having these issues is because you're allowing your working trees to become too out of sync. If everybody is working on the same module, then those developers should be trying to retain lock-step. Even if developer A (the breaker) doesn't have access to the code of developer B and therefore can't update his function calls - committing smaller changesets and merging more often, where the overhead in assessing changes is tiny, will wipe out 99% of these issues. If you can't see the forest for the trees, then issues are going to slip through.
> Yes, and we are all human so sometimes, despite heroic efforts, we will all make stupid mistakes as well as subtle mistakes.
Now, once we made the mistake, do we want our tool to insidiously hide this mistake from us, making it as expensive as possible to punish us for our mistake? Or do we want a tool that tells me ASAP "Hey dude, you made a stupid mistake over there"?
Except in JS, the code itself isn't a mistake. It's your problem - JS has nothing to do with ensuring that you keep your codebase bug-free.
> And to do this job, I have tools like languages that help me find those mistakes quickly.
Then use them, and stop complaining about something that you don't even use.
> Making mistakes isn't "sloppiness", it's human.
Making the same mistake repeatedly and then blaming your tools is sloppiness however you dress it up.
> If one language makes writing a non-shitty codebase harder than a different language, it is also the fault of that language.
It's not harder, it's just different. If you learn the language and its subtleties, then you won't have these problems.
> If changing internal functions results in breakages, then I don't know what else you'd call it except a breaking change.
It's not the change itself that broke things. It's the combination of two changes that you got when you used "git pull".
> Not if you're making small commits, often. Changing a function signature necessitates the modification of all callers to that function. This would be a large commit which includes all of necessary changes to ensure that the software remains in a stable state.
Small commits make this less likely -- but it can still happen.
> This is still just a process problem - if you committed and merged more often, these issues wouldn't arise. The reason you're having these issues
I'm not having these issues because I am wise enough to avoid JS.
> because you're allowing your working trees to become too out of sync
CI is great, but for some major changes, incremental changes are not always a possibility. Sometimes you have to break things temporarily in order to change the way things work in a significant way. This is typically done in a side-branch. Integrating that side branch with all the changes will require going over all functions that changed manually, to see if the signatures now mismatch their callers (solving the halting problem, in the general case), because even UT can easily miss it.
> committing smaller changesets and merging more often, where the overhead in assessing changes is tiny, will wipe out 99% of these issues
What do you propose to do about the 1% of issues that still plague the codebase?
> Except in JS, the code itself isn't a mistake. It's your problem - JS has nothing to do with ensuring that you keep your codebase bug-free.
The code itself is a mistake. You meant to call something with (x,y,z), instead you called it with (x,y/z). Now the language will do its best to hide this problem from you, so you can discover it as late as possible, when it is most expensive.
> Then use them, and stop complaining about something that you don't even use.
The thing is, I was hoping to get the perspective of someone who does use this language, to see that point of view, but the point of view seems to be "languages should not help you write good programs or find your errors", "just don't make bugs", and "change your process to accomodate JS to reduce this risk that should not exist in the first place".
> Making the same mistake repeatedly and then blaming your tools is sloppiness however you dress it up.
Who says it's the "same mistake repeatedly"? There are many different mistakes that could be made non-repeatedly by many different developers that would get caught if function signatures were verified sanely but instead hidden by JS.
> It's not harder, it's just different. If you learn the language and its subtleties, then you won't have these problems.
So you just "learn" to never make mistakes. I get it.
Silencing an error would be a problem, but in JS, it's not an error, because there's no concept of "wrong numbers of function arguments" built into the language. That's not to say you can't inspect the number of arguments yourself and throw an error, if some situation warrants it. But you don't have to do this. It's a very flexible, dynamic language. In some ways this flexibility makes things easier and more expressive, in other ways it necessitates more manual checking (or slower debugging). There's no catastrophe, just design differences.
> ... in other ways it necessitates more manual checking (or slower debugging). There's no catastrophe, just design differences.
See, there's the problem. Glossing over issues by explaining them away as "design differences". Nothing about an expressive language necessitates making life hard for the programmer. If your function call doesn't match the signature then it is very likely to be in error, and instead of failing silently the language should make such mistakes easy to spot. I like how most other dynamic languages require you to be more explicit about function parameters (with the exception of PHP).
> If your function call doesn't match the signature
Depending on what constitutes function signature. I agree with “design difference” argument. Someone has to make design decisions, even if someone else doesn't agree with them.
The problem is the design here is to trade errors that could be detected with cryptic bugs that can slip through. Or alternatively, adding insane per-function overhead/testing to manually cover signature checking.
It's still a programmer error when they accidentally call a function with 2 arguments when they meant to call it with 3. The fact that the language can't inform them of the error doesn't change that.
That's great if it's your function that's the problem. Less so if it's someone else's.
And it's not only these kinds of errors that can cause silent failure. I've had it on missing brackets, on missing commas, on failure to include/require the right source file etc, etc. No error message, no warning, no log entry, no nothing. Just silence. And a blank output. Not overly helpful.
A) Silently ignore errors in param counts, get cryptic bugs later when a trivial merge changes a function signature, or when changing a function signature.
B) Add explicit code to check the parameter counts at a huge cost (a per-function overhead!) along with extra tests for this silly thing for each and every function. This overhead is insane!
I have to choose between cryptic bugs and insane overhead, all for what? So you can use "args" and not "*args"?
But you do see why people are complaining, right? You are having to manually write thousands of tests to check something that is trivial for a compiler to check.
This is just an absurd complaint, it's a dynamic language, if you want compiler forced type checking, use a static language. Dynamic languages are not broken because they don't behave like static languages.
I'm not missing the point, and I don't agree that it hides an error and gives a cryptic bug. Messing with a function signature and not updating callers of that function is not a bug in the language, it's a bug in the programmer and will result in runtime bugs in any dynamic language. If you require X number of args, then assert that they aren't undefined. If you presume callers pass in X number of args in a variable args language, and then change the required args, you're the bug, not the language.
> I'm not missing the point, and I don't agree that it hides an error and gives a cryptic bug.
It hides the error by carrying on, despite having the wrong number of arguments, and executing code with thus necessarily wrong inputs.
> Messing with a function signature and not updating callers of that function is not a bug in the language, it's a bug in the programmer
When editing code, you routinely change the function signatures of hundreds of functions. Of course you're going to miss some, some of the time. Human errors happen, and good languages help us deal with them.
Also, every time you pull code from another repository, function signatures all over the place change. Some of those may be functions your currently edited code is calling. This means every little divergence requires reviewing every single signature change or cryptic bugs will result.
> and will result in runtime bugs in any dynamic language.
It will result in runtime errors in dynamic languages. Errors that are visible, and difficult to ignore. That means the code gets fixed. UT triggers it trivially.
Whereas with Javascript, even code under UT can easily pass accidentally when wrong numbers of arguments are used.
This Dijkstra quote is relevant:
> It was a significant improvement that now many a silly mistake did result in an error message instead of in an erroneous answer. (And even this improvement wasn't universally appreciated: some people found error messages they couldn't ignore more annoying than wrong results, and, when judging the relative merits of programming languages, some still seem to equate "the ease of programming" with the ease of making undetected mistakes.)
> If you require X number of args, then assert that they aren't undefined
That captures half of the bugs (too few arguments), for a large overhead (an extra line for almost every argument in every function).
> If you presume callers pass in X number of args in a variable args language, and then change the required args, you're the bug, not the language
Every time you change code, there is potential to insert bugs. Of course all bugs originate from programmer errors. The tools can work with us to find these errors and mitigate them, or they can give us hell.
> That captures half of the bugs (too few arguments), for a large overhead (an extra line for almost every argument in every function).
You don't have to check every every arg to check the count is correct if that's something you're concerned about. Nor does checking args are undefined require a line per since you could check them all with a single assert.
If you're the type who has constant bugs from wrong arg counts, use another language that better suits your programming style, but it's not a problem everyone has.
And Dijkstra despised OO, and came from a much different time, I don't much care for many of his opinions. Alan Kay is more my style.
> You don't have to check every every arg to check the count is correct if that's something you're concerned about. Nor does checking args are undefined require a line per since you could check them all with a single assert.
That's true, but the overhead is still relatively huge.
> If you're the type who has constant bugs from wrong arg counts, use another language that better suits your programming style, but it's not a problem everyone has
I'm the type of programmer who tries to avoid errors as much as I can, but still make them as I am human, as we all are.
One of the possible errors that's really easy to make is forgetting to grep for callers of a function you just changed. Of course 99 out of 100 times you remember, but 1 out of 100 you will forget.
Another possible error is remembering to change the function signature, but just having a typo or mistake.
And finally, even if you make no errors at all -- when you pull from the server you get a bunch of function signatures and calls changed "under you feet", so any changes you had already pending (perhaps in different files) are now potentially silently invalidated, and there won't even be a runtime error to tell you about them.
There is really no real benefit to this behavior at all (beyond backwards compatibility of course). Explicit rest-of-args cost nothing.
Error messages are superior to wrong behavior, and this behavior is simply insane.
In JS, sending the "wrong" number of arguments is frequently a feature. There's no concept of language-level function overloading, and it allows for the authorship of functions that take a variable or unbounded number of arguments (useful when coding in a functional paradigm).
That "feature" would be better with an explicit language construct such as *args or params args[], though. As with so many complaints about JavaScript, it's the default behaviour that is a problem.
I'd say it's worse than a default behavior, since there's no sane way to reverse the default. Are explicit arg list checks really an option, when you want to opt out of the default? I'd say that's not practical at all -- so it's really worse, as there's no practical opt out of this.
I think the way libraries like jQuery use this behaviour to define their own undefined that is indeed undefined is rather neat, the whole of jQuery is wrapped in:
This part of Javascript sounds the most absolutely insane to me: Silencing an error like that is catastrophic.