Possible bug with unknown args to function? #1341
Replies: 14 comments
-
Posted at 2019-08-16 by Robin Fri 2019.08.16
Aren't all bugs really 'Undocumented Features'? Hello *Windy City* @jrh from an Espruino neighbor 100 miles N.W. of you. Waukesha, WI home of Les Paul inventor of the solid body electric guitar. There are at least two of us here in the Midwest. Welcome to the world of Espruino! Curious about your post, I tested the same on an EspruinoWiFi, and verify the same output. ``` >foo( 100 ) 100 Uncaught ReferenceError: "1" is not defined ``` But looking under the hood reveals the culprit. I copied your snippet verbatim here for ease of others to copy and follow along as well.
Q: What is the container arguments ?
When we add this line inside the function and run, we get:
So we have a container that is an object that we know from experience, massages the values or arguments that are passed to the function parameters.
So now we have our test snippet:
Now lets proceed to the actual perceived error:
This is informing us that as we are dealing with an object that holds an array of values that when referenced with an 'i' indexer Let's now take a peek at the function call:
And for the *BIG SURPRISE!*, I actually thought I had the obvious answer, until I did a bit more testing. Had to wrap the function contents in a try/catch to allow processing to continue and give us a bit more detail.
Running our test produces the same error.
and then on to two additional lines for the Coup de Gras:
provides some additional information, but we still need a bit more, however
Final test is to modify what is passed as the parameter list. We'll change the function definition to have just a single 'x' parameter foo( x )
```
function foo(x) {
console.log( typeof( arguments ) );
console.log( arguments.length );
try { console.log( arguments[0] ); for ( var i=0; i < arguments.length; i++ ) { } catch(e) {
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by maze1980 Yes it's a bug. As workaround define the function without arguments,
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by jrh I see the workaround works in node as well. Thanks for the tip!
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by Robin Sat 2019.08.17
What basis is being used to make that determination? The behavior of Anybody check the spec?
See section 17 ECMA spec > http://www.ecma-international.org/ecma-262/10.0/index.html#sec-method-definitions Also check out sections 14, 6 and 9 on the argument and exotic objects along with function definitions Specifically this passage: There seems to be a mis-understanding of the parameter list and what an argument is. Here is an easy read: > https://codeburst.io/parameters-arguments-in-javascript-eb1d8bd0ef04 We the coder define the parameter list that a function container will process. In this manner, the function may act on pre-determined arguments (the value of a parameter) knowing the exact parameter count. By design, and specifically addressed in the ECMA specification, when fewer arguments (the values) are passed to a function through it's parameter list, those arguments take on a value of undefined. While there may be rare instances when more arguments are passed, it can be seen that without the defined parameter list, the function won't have sufficient information on what to do with the additional un-linked values. Back to the original function from #1 as defined with two parameters: ``` function foo(x,y) { for ( var i=0; i < arguments.length; i++ ) { console.log( arguments[i] ); } } ``` Here we have exactly two parameters defined in function foo(x,y) . When we pass two arguments, then the indexer of the arguments array container will correctly report what is passed.
When more arguments are passed, we can see that the count matches as it should.
But, when using fewer arguments, per the specification, the omitted parameter arguments contain the value undefined. As the function requires valid values and as spelled out in the note from #2 link above, the arguments array will report what is defined in the function parameter list. The reason the error
appears is from incorrect Javascript as I pointed out in detail within the #2 explanation. Two obvious flaws here. Attempting to pass a different number (1) of arguments to a function that is defined (2) by the coder, then expecting an array (1 valid) to produce valid output, when the rules to passing (only 1) the correct number of parameters contradicts the exact definition (2) the coder intended. That non-array element request is similar to this snippet
As passing one argument to a two parameter list will result in an undefined value, the arguments array is unable to produce a valid response for the second value as there is only one valid argument that the call to function foo() passes. Therefore the array indexer only contains one reference and that is to element[ 0 ]. Attempting to print out to the console an un-referenced element[ 1 ] therefore will produce the error that is introduced from a bad coding practice. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by maze1980 Whatever. For one, foo is not an build-in function so the reference to this part of the specs is not substantial. The linked codeburst.io article states "arguments.length indicates the exact number of arguments which does not depend on the number of parameters in the function definition.". Maybe your understanding of the spec is correct. But all other JavaScript implementations have a different understanding. Being the only to follow the spec is a bug - from the user point of view. Because it's incompatible with the rest of the world. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by @allObjects Building function's context (frame / scope) and its variables / scoped variables, every entry in the argument list of the function is a variable known to the that frame. I use the technique to pass less arguments than declared in the list of function arguments for multiple reasons. The simple one is optional arguments and check their presence in the function. The more elaborate one is to 'declare' local variable(s) without having to spend the space for the extra Comparing Espruino's JS w/ browser (and node) JS, this is a difference. I though do not see a reason why this cannot be fixed... I'm sure 'Espruino' knows when it runs out of passed arguments and set arguments and it's length accordingly... but it may need to store the declared variables somewhere else for its own housekeeping / frame management / usage 'count' / garbage collect... Arguments |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by Robin
Yes, exactly. So why would a coder define a function with a specific number of parameters expecting an exact return response, then expect Javascript or any language that supports methods and functions, to magically to produce the same desired result when that same coder is only passing one valid argument? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by @allObjects ...it is all in the eye of the beholder / implementer and the specs, and what we know is that specs are not always as comprehensive (complete) as we think, and some things are not really intentional but become - grandfathered/grandmothered - a useful feature, either internally/private for the implementer or externally/public. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by Robin Sat 2019.08.17
That is an article, of one author's opinion describing generalized Javascript and is not a design specification. The link to the article was to reveal by definition the difference between a parameter list and what an argument is. It isn't there to imply that what that author wrote is how Espruinio Javascript works. There is an enormous amount of effort that @gfwilliams and others put in to staying as accurate as the ECMA spec defines. As @allObjects points out in #9, under some circumstances, it isn't possible to be 100% compliant.
Yes, agreed. And that is why we have specifications for each of the different implementations. This page isn't a specification as such, but does accurately describe each object and function as designed and utilized by Espruino. While it might be that the behavior of the This is why reviewing each method in the reference section is necessary during the design phase in order to avoid erroneous coding pitfalls as pointed out in this thread. I still get the impression that it is not understood, that it is an impracticality to expect a Javacript statement to output a valid value from an array that has an indexer that was assigned a value of 'undefined'. e.g.
will output an error when it is assigned 'undefined' or was never initialized in the first place, |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-17 by Robin Sun 2019.08.18 Proposed Solution If the insistence on sending fewer than the defined number of function parameters is still desired, a proposed solution would be to range check the arguments as any prudent developer should do. We'll perform that task with the
The above solution, unlike the #3 work around allows for the design requirement of two parameters x and y in function
The function definition containing two parameters is to the original poster's specification, along with the iteration over the arguments list without error. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-18 by maze1980 Parsing a variable of type "undefined" creates an error:
So there are two bugs: arguments.length is not updated (documented https://www.espruino.com/Reference#l__global_arguments). arguments fails for undefined arguments (not documented). |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-18 by @allObjects
and
...quite some statements. For the first - may be reality reads ...have each their own different understanding because for the second: all - and that's a lot of, not just Browser JS, node JS, Espruino, and not mentioning the (incomplete) rest of the world - all of them live and have to keep living proudly their 'up-bringing'... like HMTL which came to be without specs - just by doing - and and trying to get it really (cleanly) spec'd afterwards with XHMTL 1.0 / HTML 4.01 failed miserably... in regard to it's (mattering) intention... blog.codinghorror.com: html validation - does it matter?. This is quite an old (2009/03 - past 10 year anniversary) article... and the discussion ran quite hot then... and: today? Today, some aspects of the context of html and related set of technologies - that's why it is now called HTML 5 - are obviously still running hot. But let's not forget the context: for a lot/ some of the CS community the bad in JS (still) outweighs the good, despite the grown popularity / spread and knowledge - avaScript: The Good Parts- by Douglas Crockford: Most programming languages contain good and bad parts, but JavaScript has more than its share of the bad, having been developed and released in a hurry before it could be refined...... but the difference to many other hurried things it was refine-able (not like Java, which had to change some of its core to become useable... and it was not rushed from a time-wise, but architecturally... it had forgotten - or missed out - on aspects learned from the late 50' thru the early 80'... even though it claims to have chosen the best of the best - at that time ...a ramble about my love-h... or h...-love for Java, and that's a lot of daily bread). I did not like the browser war nor do I like this js war. The real issues are: Is the (application / business) problem understood? - If If we have doubt in the suitability of the tools or any of the available tools and the skills we have, let' Luckily, runtime environments - stacks - have refined themselves too over time - thanks to effort getting (IEEE / IETF shared) specs done and adhered to and last but not least thanks to competition on the market... Talking though to people from different camps, preferences are still alive... and may never go away, even after all things follow the specs... or more so all have adopted - accepted / implemented - each other's (real?) flaws (and goodies) - and completely different, new but shared solutions, so that code can be moved around... that's what I get the impression from today's HTML5 world and their most prevailing application environment(s). With IoT and Espruino is it a bit different... solutions barely have the intention to be portable between stacks, because they run not on generic or universal platforms. The solutions are very targeted and specific... and therefore cater to a lot of specifics. In the task at hand - When it comes to the other aspect - ReferenceError - it can be refined too: initially JS did not complain about undefined references, it just assumed that it is intentional. Therefore it has been introduced in Espruino so that such issues of undefined can be detected much more easily... also by maker's of whom the majority do not have a CS degree and life long professional CS deformation... How ReferenceError has been implemented may even be hampered by the fact of how JS defines undefined and most of the time understands undefined, but is refine-able as well. Concluding... JS also knows about null - which I use as a defined undefined vs. the undefined undefined. That sounds weird, but is my solution for the issue @maze1980 may have and tries to find a solution for. If I code something, it always - when I'm at fully capacity - intentional and has a reason / purpose to serve... and defined - otherwise it would be a waste of my time and I would not code it - and so I make a distinction between |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-19 by Robin Mon 2019.08.19 Thank you @allObjects for the link to the thirty or so Javascript engines. An eye openner. The Douglas Crockford book brings back early memories.
which of course is not true Refer to link in #5 'ECMA specification' Beneath heading 'The Reference Specification Type'
Beneath heading 'Well-Known Intrinsic Objects'
Beneath heading 'ReferenceError'
Using code snippet from #12 L1 clearly defines a function requiring two valid initialized primitive types. It is the designers responsibility to validate that the expected data, matches the function definition. It is also the responsibility of the caller to pass valid data matching the function prototype. Specification recommendations. L7 violates passing initialized arguments to a known function that defines that requirement. Although a bad practice, it is allowable and valid Javascript. It is an 'unresolved binding issue', however.
No where in lines L2 through L6 is there a validation check on the arguments passed to the function. Javascript allows this as the syntax is valid, although also a bad practice. As four primitive types are passed at L7, they initialize the arguments object, with elements [0] and [2] set to the 'undefined' primitive type. Another bad practice.
Also verified by the Mozilla group MDN web docs.
Note that even with element indicies, object arguments is it's own object type and not derived from object Array Review the last snippet in #5 demonstrating undefined array elements for the following:
The output is as expected and exactly to ECMA specification. No bugs. Thank you @maze1980 for presenting your snippet in #12 that demonstrates careless coding deficiencies that can lead to undesired results. One other possible solution is to implement the redefinition example @allObjects provided in last pp. in #13, . . . and; Again my recommendation is to use the argument validation code as suggested in the fully functional working example within #11 to avoid attempting to access objects that are not properly initialized. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-08-27 by @gfwilliams I'm just working my way through the forum and I don't have time to read all of this thread, but @maze1980's post looks spot on to me... http://forum.espruino.com/conversations/337375/#14864281
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Posted at 2019-08-16 by jrh
I was testing espruino on the Linux command line (while waiting for my boards to be shipped) and ran across this error. Is this a bug, or a feature?
The source was cloned from github and compiled on Ubuntu 16.04.6 LTS. I got the same error on an OS X build as well. It was built with the following commands:
I saw this post Functions with unknown amount of args. but I didn't get the same results.
Beta Was this translation helpful? Give feedback.
All reactions