Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #39628 > unrolled thread
| Started by | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| First post | 2021-03-13 15:32 +0300 |
| Last post | 2023-04-22 08:47 -0700 |
| Articles | 20 on this page of 48 — 7 participants |
Back to article view | Back to comp.lang.javascript
input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-13 15:32 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-13 15:16 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-14 18:51 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-14 16:15 +0000
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-14 18:31 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-14 22:27 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-14 23:44 +0000
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-15 06:41 -0700
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-14 22:17 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-14 23:28 +0000
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-15 06:39 -0700
Re: input/output parameters Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-03-14 22:32 +0000
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-15 06:36 -0700
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-20 14:49 +0300
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-20 11:59 -0700
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-20 13:07 -0700
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-20 19:29 +0000
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-20 20:35 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-15 00:27 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-14 23:51 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-20 14:56 +0300
Re: input/output parameters Jon Ribbens <jon+usenet@unequivocal.eu> - 2021-03-20 15:08 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-21 15:16 +0300
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-21 08:46 -0700
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-04-10 14:54 +0300
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-20 12:05 -0700
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-21 15:58 +0300
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-15 06:43 -0700
Re: input/output parameters Silvio <silvio@internet.com> - 2021-03-15 18:01 +0100
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-16 18:06 +0000
Re: input/output parameters Silvio <silvio@internet.com> - 2021-03-16 23:58 +0100
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-17 19:14 +0000
Re: input/output parameters Silvio <silvio@internet.com> - 2021-03-17 23:46 +0100
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-18 18:04 +0000
Re: input/output parameters Silvio <silvio@internet.com> - 2021-03-22 00:39 +0100
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-23 10:44 +0000
Re: input/output parameters Silvio <silvio@internet.com> - 2021-03-30 00:33 +0200
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-31 19:53 +0100
Re: input/output parameters Silvio <silvio@internet.com> - 2021-04-01 01:17 +0200
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-04-01 18:02 +0100
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-20 15:50 +0300
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-20 18:52 +0000
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-21 17:35 +0300
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-21 08:50 -0700
Re: input/output parameters Anton Shepelev <anton.txt@gmail.com> - 2021-03-21 19:31 +0300
Re: input/output parameters John G Harris <niam@jghnorth.org.uk.invalid> - 2021-03-21 19:27 +0000
Re: input/output parameters "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-03-20 13:02 -0700
Re: input/output parameters Postiljon Petskin <yyyyyyyyyyyywwwww@zohomail.eu> - 2023-04-22 08:47 -0700
Page 1 of 3 [1] 2 3 Next page →
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-13 15:32 +0300 |
| Subject | input/output parameters |
| Message-ID | <20210313153232.40fa0c8b0adf07d7e807084d@gmail.com> |
Hello, all
I started learning JavaScript but yesterday, but am already
stuck at implementing input/output parameters. As I
understand, they are not part of the language, yet I find
them very convenient for normal procedural programming. For
example, they allow returning a boolean flag and using
functions inside `if` tests, similar to the very convenient
TryParse() and TryGetValue() functions in C#:
TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
TryGetValue: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue
Unfortunately for me, JavaScript seems to compensate the
lack of in/out parameters with much more complicated
functional and object-oriented mechanisms. I therefore have
tried to implement them myself, but have not come up with a
satisfactory solution. The examples below demonstrate a
function for integer division that stores the result in
variable and returns a boolean value indicating whether the
division was exact:
// for bi-direction in/out parameters, return a code that
// creates an anonymous object storing the the value *and*
// setter clousure:
function out_1(vn)
{ return "x => " + vn + " = x"; }
function int_div_1(a, b ,c)
{ var /*integer */ r; // ratio
var /*boolean */ x; // result is exact
r = Math.floor(a / b);
x = r * b === a;
c( r );
return x;
}
function out_2( vn, val, ret )
{ return `${vn} = ${val}, ${ret}`; }
function int_div_2(a, b, vn)
{ var /*integer */ r; // ratio
var /*boolean */ x; // result is exact
r = Math.floor(a / b);
x = r * b === a;
return out_2(vn, r, x);
}
{ let /*integer */ ratio;
let /*boolean */ exact;
exact = int_div_1(7, 3, eval(out_1("ratio")));
console.log(`7/3: ratio = ${ratio}; exact = ${exact}.`);
exact = int_div_1(6, 3, eval(out_1("r")));
console.log(`6/3: ratio = ${ratio}; exact = ${exact}.`);
exact = eval(int_div_2(7, 3, "ratio"));
console.log(`7/3: ratio = ${ratio}; exact = ${exact}.`);
exact = eval(int_div_2(6, 3, "ratio"));
console.log(`6/3: ratio = ${ratio}; exact = ${exact}.`);
}
Can you think of better way to emulate output parameters,
and preferable also bi-directional input/output parameters?
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-13 15:16 +0000 |
| Message-ID | <slrns4plpr.4fd.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39628 |
On 2021-03-13, Anton Shepelev <anton.txt@gmail.com> wrote:
> Can you think of better way to emulate output parameters,
> and preferable also bi-directional input/output parameters?
You should probably try and program in the style of the language you are
using, rather than try and force the langauge you are using to work in
the style of a different language. But you can do this, for example:
function multiplyAndDivide (data) {
data.multiplied = data.a * data.b
data.divided = data.a / data.b
}
const values = { a: 2, b: 4 }
multiplyAndDivide(values)
console.log(values.multiplied, values.divided)
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-14 18:51 +0300 |
| Message-ID | <20210314185124.0bcbab76d172caf076ac3839@gmail.com> |
| In reply to | #39630 |
Jon Ribbens:
> You should probably try and program in the style of the
> language you are using, rather than try and force the
> langauge you are using to work in the style of a different
> language.
What is the JavaScript style of implementing TryParse() and
TryGetValue()?--
TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
TryGetValue: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue
The whole point of those and similar functions is their
usefulness as the condition of `if' and `while' statements,
e.g.:
while( read_next( stream, out element )
{ // process the element
}
What alternative(s) does JavaScript propose?
> But you can do this, for example:
>
> function multiplyAndDivide (data) {
> data.multiplied = data.a * data.b
> data.divided = data.a / data.b
> }
>
> const values = { a: 2, b: 4 }
> multiplyAndDivide(values)
> console.log(values.multiplied, values.divided)
In this example, both calculated values are part of the
result of a successful calcualtion, so it is not analogous
to my case, where I would be forced to return, say, an error
flag, the error text, and a numerical result illogically
grouped together in an object. Your example, on the other
hand, is all right.
The major advantage of output variables is that they let a
function modify the values of the caller's scalar varables
in a transparent way. Passing an object to modify some of
its fields is not as transparent, whereas the need to
"upack" the object's properties back into normal variables
is quite inconvenient.
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-14 16:15 +0000 |
| Message-ID | <slrns4sdlm.4fd.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39637 |
On 2021-03-14, Anton Shepelev <anton.txt@gmail.com> wrote:
> Jon Ribbens:
>> You should probably try and program in the style of the
>> language you are using, rather than try and force the
>> langauge you are using to work in the style of a different
>> language.
>
> What is the JavaScript style of implementing TryParse() and
> TryGetValue()?--
>
> TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
parseInt() - returns `NaN` on failure
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
> TryGetValue: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue
Map.get() - returns `undefined` if the key isn't in the mapping
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
> The whole point of those and similar functions is their
> usefulness as the condition of `if' and `while' statements,
> e.g.:
>
> while( read_next( stream, out element )
> { // process the element
> }
>
> What alternative(s) does JavaScript propose?
It would depend on the details of what you're doing. A lot of stream
handling stuff in JavaScript was added before Promises, so you can't
do the above and instead you'd be adding callbacks or event handlers.
>> But you can do this, for example:
>>
>> function multiplyAndDivide (data) {
>> data.multiplied = data.a * data.b
>> data.divided = data.a / data.b
>> }
>>
>> const values = { a: 2, b: 4 }
>> multiplyAndDivide(values)
>> console.log(values.multiplied, values.divided)
>
> In this example, both calculated values are part of the
> result of a successful calcualtion, so it is not analogous
> to my case, where I would be forced to return, say, an error
> flag, the error text, and a numerical result illogically
> grouped together in an object. Your example, on the other
> hand, is all right.
Throw an exception on error then.
> The major advantage of output variables is that they let a
> function modify the values of the caller's scalar varables
> in a transparent way. Passing an object to modify some of
> its fields is not as transparent, whereas the need to
> "upack" the object's properties back into normal variables
> is quite inconvenient.
Don't unpack them then. Or 'return data' from the function and use
destructuring:
function multiplyAndDivide (a, b) {
if (b === 0) throw new Error('division by zero')
return { multiplied: a * b, divided: a / b }
}
const { multiplied, divided } = multiplyAndDivide(2, 4)
console.log(multiplied, divided)
Or if you really, *really* want output arguments then, er, don't use
JavaScript and use a different language that you like better instead.
[toc] | [prev] | [next] | [standalone]
| From | John G Harris <niam@jghnorth.org.uk.invalid> |
|---|---|
| Date | 2021-03-14 18:31 +0000 |
| Message-ID | <3bls4ghfb0bas51ic8ki23r2i50v86lk9u@4ax.com> |
| In reply to | #39638 |
On Sun, 14 Mar 2021 16:15:50 -0000 (UTC), Jon Ribbens <jon+usenet@unequivocal.eu> wrote: <snip> >Or if you really, *really* want output arguments then, er, don't use >JavaScript and use a different language that you like better instead. Yes, you can tell a function what function you want it to use, you can tell it what object you want it to read/write, but you can't tell it what variable you want it to update. John
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-14 22:27 +0300 |
| Message-ID | <20210314222707.1bf72c4857dcd8d88867857c@gmail.com> |
| In reply to | #39641 |
John G Harris:
> Yes, you can tell a function what function you want it to
> use, you can tell it what object you want it to
> read/write, but you can't tell it what variable you want
> it to update.
Can you please explain to me how the `rvar' solution from
this answer is supposed to work:
An answer to:
Pass variables by reference in JavaScript:
https://stackoverflow.com/a/21487151/2862241
Online interpreters complain about a missing `window' global
context. But after I passed `this' as the third argument to
all the invocations of `rvar' it still did not take off:
rvar('test_ref_number', 5, this);
test_ref_number.value === 5; // true
---
ReferenceError: test_ref_str is not defined
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-14 23:44 +0000 |
| Message-ID | <slrns4t7uj.4fd.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39643 |
On 2021-03-14, Anton Shepelev <anton.txt@gmail.com> wrote: > Can you please explain to me how the `rvar' solution from > this answer is supposed to work: > > An answer to: > Pass variables by reference in JavaScript: > https://stackoverflow.com/a/21487151/2862241 It's an abomination, presumably created as an experiment rather than a serious suggestion. Do not do anything like this. It's trying to create a property on the global context that has a setter and getter defined to make it look like its value is one thing but actually it's an object and the apparent value is stored elsewhere. It's an appalling bodge and it barely works at all, let alone being a good idea to use in practice.
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2021-03-15 06:41 -0700 |
| Message-ID | <40e83619-0d1f-47f8-a75e-5df2e745503dn@googlegroups.com> |
| In reply to | #39643 |
On Sunday, March 14, 2021 at 2:27:14 PM UTC-5, Anton Shepelev wrote:
> Can you please explain to me how the `rvar' solution from
> this answer is supposed to work:
>
> An answer to:
> Pass variables by reference in JavaScript:
> https://stackoverflow.com/a/21487151/2862241
>
> Online interpreters complain about a missing `window' global
> context. But after I passed `this' as the third argument to
> all the invocations of `rvar' it still did not take off:
>
> rvar('test_ref_number', 5, this);
> test_ref_number.value === 5; // true
> ---
> ReferenceError: test_ref_str is not defined
You need to understand how 'this' works in JavaScript:
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this>
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-14 22:17 +0300 |
| Message-ID | <20210314221723.d4bccc22ee2647d1b474151a@gmail.com> |
| In reply to | #39638 |
Jon Ribbens:
> parseInt() - returns `NaN` on failure
I know and use it in my first attempt to get something like
out parameters:
function tryparse_int_1(s, cb)
{ var res = parseInt(s);
cb(res);
return !isNaN( res );
}
function test_1(s)
{ var /* inreger */ i;
if( tryparse_int_1( s, x=>i=x ) )
console.log(`String "${s}" is parsed as integer ${i}.`); else
console.log(`String "${s}" does not start with an integer.`);
}
test_1("47");
test_1("forty-seven");
> Map.get() - returns `undefined` if the key isn't in the
> mapping
I see -- JS takes avail of its dymamic typing by returning
`undefined' for both mutable and immutable values, but that
approach requires two lines instead of one, i.e.:
elem = map.get( key );
if( elem == undefined )
{ /*handle error*/ }
unless I use a feature of C-like languages that an
assignment is also an expression with a value:
var /*integer*/ int;
var /*boolean*/ ok;
if( !isNaN(int = parseInt("5")) )
console.log("ok: " + int); else
console.log("not at int.");
> > while( read_next( stream, out element )
> > { // process the element
> > }
> >
> > What alternative(s) does JavaScript propose?
>
> It would depend on the details of what you're doing. A lot
> of stream handling stuff in JavaScript was added before
> Promises, so you can't do the above and instead you'd be
> adding callbacks or event handlers.
I did not mean streams in particular but the programming of
a while loop that reads elements from a source until it is
exhausted. It may be rows from a recordset or tokens from a
string. I think I can do it this way:
while( ( element = read_next( stream ) != undefined )
{ // process the element
}
// or:
while( true )
{ element = read_next( stream )
if( element == undefined ) break;
// process the element
}
But it is a choice between a bit clumsy and a bit wordy.
> Throw an exception on error then.
I generally dislike exceptions and try to use normal control-
flow instead. My rule for exceptions is identical to
Joel's: catch them as early as possible, and never thow them
yourself:
"Exceptions", by Joel Spolsky
https://www.joelonsoftware.com/2003/10/13/13/
Ok, I do throw exceptions by way of asserts, if my program
can afford crashing at all.
> Or 'return data' from the function and use destructuring:
> [...]
> const { multiplied, divided } = multiplyAndDivide(2, 4)
> console.log(multiplied, divided)
Thanks for another alternative, I will certainly consider
it, although I find it somewhat aesthetically displeasing to
have more than one token on the left-hand side of an
assignment, but it may be better than passing several
anonymous setters or using eval:
[ok, err_text, result] = get_temp_file();
This is shorter and cleaner than any of the alternatives I
know of.
> Or if you really, *really* want output arguments then, er,
> don't use JavaScript and use a different language that you
> like better instead.
Sometimes it is not an option. I am learning to live with
JavaScript.
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-14 23:28 +0000 |
| Message-ID | <slrns4t71n.4fd.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39642 |
On 2021-03-14, Anton Shepelev <anton.txt@gmail.com> wrote:
> Jon Ribbens:
>> Throw an exception on error then.
>
> I generally dislike exceptions and try to use normal control-
> flow instead. My rule for exceptions is identical to
> Joel's: catch them as early as possible, and never thow them
> yourself:
>
> "Exceptions", by Joel Spolsky
> https://www.joelonsoftware.com/2003/10/13/13/
Wow. Preusmably Joel in 2003 had barely even tried using a language
with proper exceptions, since his opinions in that article are
absolutely terrible.
>> Or 'return data' from the function and use destructuring:
>> [...]
>> const { multiplied, divided } = multiplyAndDivide(2, 4)
>> console.log(multiplied, divided)
>
> Thanks for another alternative, I will certainly consider
> it, although I find it somewhat aesthetically displeasing to
> have more than one token on the left-hand side of an
> assignment, but it may be better than passing several
> anonymous setters or using eval:
>
> [ok, err_text, result] = get_temp_file();
>
> This is shorter and cleaner than any of the alternatives I
> know of.
I'd again suggest that you let yourself be guided by the styles
used by people who have been using the language for longer.
In this case, perhaps:
https://github.com/raszi/node-tmp/blob/master/README.md#synchronous-file-creation
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2021-03-15 06:39 -0700 |
| Message-ID | <24877557-9766-4dbd-94f6-633fbc890980n@googlegroups.com> |
| In reply to | #39642 |
On Sunday, March 14, 2021 at 2:17:30 PM UTC-5, Anton Shepelev wrote:
> I see -- JS takes avail of its dymamic typing by returning
> `undefined' for both mutable and immutable values, but that
> approach requires two lines instead of one, i.e.:
>
> elem = map.get( key );
> if( elem == undefined )
> { /*handle error*/ }
Conditional properties exist:
elem = map.get(key) ?? defaultValue
> I did not mean streams in particular but the programming of
> a while loop that reads elements from a source until it is
> exhausted. It may be rows from a recordset or tokens from a
> string. I think I can do it this way:
>
> while( ( element = read_next( stream ) != undefined )
> { // process the element
> }
> // or:
> while( true )
> { element = read_next( stream )
> if( element == undefined ) break;
> // process the element
> }
Iterators and Generators are used for this:
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators>
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2021-03-14 22:32 +0000 |
| Message-ID | <875z1t9xjc.fsf@bsb.me.uk> |
| In reply to | #39637 |
Anton Shepelev <anton.txt@gmail.com> writes:
> The whole point of those and similar functions is their
> usefulness as the condition of `if' and `while' statements,
> e.g.:
>
> while( read_next( stream, out element )
> { // process the element
> }
>
> What alternative(s) does JavaScript propose?
I suppose it depends on your style preferences. One could make a
parsing object with the stream as a member and have the various parsing
functions set an 'element' member. Then one would write
let parser = { stream: data_source };
while (parser.read_next()) {
// process parser.element
}
or you could indicate failure by returning a value that is never the
result of a successful parse, for example null, undefined or false.
Then you'd write
while ((element = parser.read_next(stream)) !== null) {
// process element
}
Or maybe you'd prefer the functions returned two values so you could use
"destructuring" to refer to them:
while ([element, status] = read_next(stream), status) {
// process element
}
Then again, some people might prefer to use exceptions. There are many,
many options.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2021-03-15 06:36 -0700 |
| Message-ID | <e52cbce2-ffaa-43f3-8d0f-6f7c82950599n@googlegroups.com> |
| In reply to | #39637 |
On Sunday, March 14, 2021 at 10:51:30 AM UTC-5, Anton Shepelev wrote:
> What is the JavaScript style of implementing TryParse() and
> TryGetValue()?--
> TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
```
let x = parseInt('145')
```
x is the number or NaN if it failed.
If you want a default value:
```
let x = parseInt('not a number') || 12;
```
Note in the latter case '0' would be treated as a failure. Slightly longer alternative:
```
let parseIntOrDefault = (x, defaultValue) => {
let result = parseInt(x, 10)
return isNaN(result) ? defaultValue : result
}
```
> TryGetValue: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue
```
let result = myMap.get(value) ?? defaultValue
```
In JavaScript operations belong to the object and not to the type. The default value is supplied by you and not implied by the type system.
> The whole point of those and similar functions is their
> usefulness as the condition of `if' and `while' statements,
> e.g.:
>
> while( read_next( stream, out element )
> { // process the element
> }
>
> What alternative(s) does JavaScript propose?
JavaScript has iterators and generators for this style of coding:
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators>
> The major advantage of output variables is that they let a
> function modify the values of the caller's scalar varables
> in a transparent way. Passing an object to modify some of
> its fields is not as transparent, whereas the need to
> "upack" the object's properties back into normal variables
> is quite inconvenient.
The problem is that it makes local reasoning more difficult. I can not simply look at a function call and know that it's simply returning a value,
I'd have to inspect the arguments to see what side-effects are potentially happening in my scope.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-20 14:49 +0300 |
| Message-ID | <20210320144942.f32b26506f67afa7a039ec2a@gmail.com> |
| In reply to | #39650 |
Michael Haufe to Anton Shepelev:
> > What is the JavaScript style of implementing TryParse()
> > and TryGetValue()?--
> > TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
>
> ```
> let x = parseInt('145')
> ```
>
> x is the number or NaN if it failed.
I know about parseInt(), but its interface is different: it
has no out parameter and no boolean return. Therefore, it
cannot be used inside a condition without additional
trickery, e.g.:
var i;
if( isNaN(i = parseInt(`d5`)))
console.log("Not a number."); else
console.log(`Parsed. The double is ${2*i}.`);
> If you want a default value:
>
> ```
> let x = parseInt('not a number') || 12;
> ```
> Note in the latter case '0' would be treated as a failure.
No, not in this case, but thanks for pointing out the
possibility.
> Slightly longer alternative:
>
> ```
> let parseIntOrDefault = (x, defaultValue) => {
> let result = parseInt(x, 10)
> return isNaN(result) ? defaultValue : result
> }
> ```
That is what I would use if I needed a default value:
function parseIntDef(s, def)
{ var res;
if( typeof(s) != "string" )
{ throw new Error("`s' is not a string."); }
if( typeof(def) != "number" )
{ throw new Error("`def' is not an int."); }
res = parseInt(s);
if( isNaN( res ) )
{ res = def; }
return res;
}
> > TryGetValue: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue
>
> In JavaScript operations belong to the object and not to
> the type.
I try not to rely on it, preferring to pass all the
necessary data in parameters.
> The default value is supplied by you and not implied by
> the type system.
I do not care about any implied default values, because I
use the out parameter only if the invocation succeeded. If
it failed and returned false, it means the dictionary does
not contain the key, and I can provide my own default value,
should I so desire.
> > while( read_next( stream, out element )
> > { // process the element
> > }
> >
> > What alternative(s) does JavaScript propose?
>
> JavaScript has iterators and generators for this style of
> coding:
>
> <https://developer.mozilla.org/en-
> US/docs/Web/JavaScript/Guide/Iterators_and_Generators>
I think it is rather complicated approach that goes way
beyond procedural programming and relies on object-oriented
and functional mechanisms (with `yield' implemented as an
entire state machine under the hood!), when all I ask for is
a simple function. OK, I can write it in JavaScript by
passing it a callback:
function read_next( stream, set_elem )
{ var res;
res = true;
if EOF( stream ) res = false;
else set_elem( NEXT( stream ) );
return res;
}
But obviously it clumsier than a plain output parameter,
about which you write:
> The problem is that it makes local reasoning more
> difficult. I can not simply look at a function call and
> know that it's simply returning a value, I'd have to
> inspect the arguments to see what side-effects are
> potentially happening in my scope.
In that sense, OOP is all about such side-effects, where a
method call may change the state of data that is not
explicitly passed to it, but is buried somewhere in `this'.
If a function changes the value of an `out' parameter, it is
not a side effect but an explicitly specified operation that
in many languages is visible in the call:
C : hasData = ReadNext( &stream, &element );
C#: hasData = ReadNext( stream, ref element );
Both of these calls change the state of `stream' and, if a
new element has been read, put it into the `element'
variable.
Remember also that I am talking about *scalar* output
parameters. They are entirely free of side effects because a
function cannot partially modifythem, as it can modify some,
but not all, fields of an object. Therefore, modification of
object members (allowed in JavaScript) is actually less
transparent than modification of scalar values (not allowed
in JavaScript).
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2021-03-20 11:59 -0700 |
| Message-ID | <94329a83-de5a-42d3-ad1f-b45a990f0e49n@googlegroups.com> |
| In reply to | #39716 |
On Saturday, March 20, 2021 at 6:49:49 AM UTC-5, Anton Shepelev wrote:
> Michael Haufe to Anton Shepelev:
> > > What is the JavaScript style of implementing TryParse()
> > > and TryGetValue()?--
> > > TryParse: https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse
> >
> > ```
> > let x = parseInt('145')
> > ```
> >
> > x is the number or NaN if it failed.
> I know about parseInt(), but its interface is different: it
> has no out parameter and no boolean return. Therefore, it
> cannot be used inside a condition without additional
> trickery, e.g.:
>
> var i;
> if( isNaN(i = parseInt(`d5`)))
> console.log("Not a number."); else
> console.log(`Parsed. The double is ${2*i}.`);
out params are not a wise feature in programming languages. They conflict with local reasoning.
parseInt is guaranteed to return a float, that includes NaN and Infinity. You would have the same problem with TryParse in C#:
```C#
double d;
var doubleSuccess = double.TryParse("NaN", out d);
Console.WriteLine(string.Format("Double parse of \"{0}\" parse = {1}", d, doubleSuccess));
// Double parse of "NaN" parse = True
```
> > If you want a default value:
> >
> > ```
> > let x = parseInt('not a number') || 12;
> > ```
> > Note in the latter case '0' would be treated as a failure.
> No, not in this case, but thanks for pointing out the
> possibility.
0 is a falsy value, so yes it would "work".
<https://developer.mozilla.org/en-US/docs/Glossary/Falsy>
> > Slightly longer alternative:
> >
> > ```
> > let parseIntOrDefault = (x, defaultValue) => {
> > let result = parseInt(x, 10)
> > return isNaN(result) ? defaultValue : result
> > }
> > ```
> That is what I would use if I needed a default value:
>
> function parseIntDef(s, def)
> { var res;
>
> if( typeof(s) != "string" )
> { throw new Error("`s' is not a string."); }
>
> if( typeof(def) != "number" )
> { throw new Error("`def' is not an int."); }
>
> res = parseInt(s);
> if( isNaN( res ) )
> { res = def; }
> return res;
> }
Also worth asking: do you want an integer, or a float? Do you want "3.14" be parsed as "3"?
Note that the following functions exist:
isFinite
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite>
parseFloat
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat>
> > > while( read_next( stream, out element )
> > > { // process the element
> > > }
> > >
> > > What alternative(s) does JavaScript propose?
> >
> > JavaScript has iterators and generators for this style of
> > coding:
> >
> > <https://developer.mozilla.org/en-
> > US/docs/Web/JavaScript/Guide/Iterators_and_Generators>
> I think it is rather complicated approach that goes way
> beyond procedural programming and relies on object-oriented
> and functional mechanisms (with `yield' implemented as an
> entire state machine under the hood!), when all I ask for is
> a simple function. OK, I can write it in JavaScript by
> passing it a callback:
>
> function read_next( stream, set_elem )
> { var res;
>
> res = true;
> if EOF( stream ) res = false;
> else set_elem( NEXT( stream ) );
>
> return res;
> }
If you only want a single step a "simple" function works with a callback. This was how it was accomplished
before iterators/generators were introduced. It's extrinsic vs intrinsic. Your while loop would become:
```
for(let element of stream()) {
// process the element
}
```
Where stream is:
```
function* stream() {
yield 1
yield 2
//etc
}
```
Which also enables spread and a number of other niceties:
```
[...stream()]
```
There is also an async version of this:
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of>
Design patterns are bug reports against your programming language and the CPS style for streams were resolved in this way.
> But obviously it clumsier than a plain output parameter,
> about which you write:
Not clumsier. You're moving where the details are handled. Either the client has to deal with it, or it is managed inside the abstraction.
> > The problem is that it makes local reasoning more
> > difficult. I can not simply look at a function call and
> > know that it's simply returning a value, I'd have to
> > inspect the arguments to see what side-effects are
> > potentially happening in my scope.
> In that sense, OOP is all about such side-effects, where a
> method call may change the state of data that is not
> explicitly passed to it, but is buried somewhere in `this'.
That depends on your definition of OOP. Side-effects are avoidable in this paradigm as well:
```
abstract class List<T>{
abstract append(item: T): List<T>
abstract length(): number
abstract remove(item: T): List<T>
}
class Empty<T> extends List<T> {
append(item: T): List<T> { return new Cons(item, this) }
length(){ return 0 }
remove(item: T): List<T> { return this }
}
class Cons<T> extends List<T> {
constructor(
readonly head: T,
readonly tail: List<T>
) { super() }
append(item: T) { return this.tail.append(item) }
length(){ return 1 + this.tail.length() }
remove(item: T) {
return this.head === item ? this.tail : this.tail.remove(item)
}
}
```
But you are correct that it is about managing state. Both Functional and OO does this.
The latter uses objects and the former uses closures.
> If a function changes the value of an `out' parameter, it is
> not a side effect but an explicitly specified operation that
> in many languages is visible in the call:
It wouldn't be a function it would be a procedure. The out parameter is the side-effect.
Threading mutable state through my program is not a positive thing. It's just as bad as John G. Harris's comment on using an object as the parameter. Mutating a parameter directly, or using it as an additional output mechanism is more complicated by definition: complecting what should be orthogonal features.
<https://en.wikipedia.org/wiki/Orthogonality#Computer_science>
> C : hasData = ReadNext( &stream, &element );
> C#: hasData = ReadNext( stream, ref element );
>
> Both of these calls change the state of `stream' and, if a
> new element has been read, put it into the `element'
> variable.
Yes, and it's a poor feature. With the above you have now tightly coupled ReadNext with the scope.
ReadNext is not a closed-expression though it is pretending to be. I can't reason about it independently, I have to understand its surrounding scope.
If I change the 'out' parameter to an 'in' parameter, how much of an impact would that be? With the more disciplined approach of relying on the 'return' statement alone you avoid these issues. Sure the compiler can help you find these issues, but that's a solution for a problem that shouldn't exist.
> Remember also that I am talking about *scalar* output
> parameters. They are entirely free of side effects
Changing the value of a variable counts as a side-effect. The following won't work when I declare 'd' as a constance:
```C#
const double d;
var doubleSuccess = double.TryParse("NaN", out d);
```
> because a
> function cannot partially modifythem, as it can modify some,
> but not all, fields of an object. Therefore, modification of
> object members (allowed in JavaScript) is actually less
> transparent than modification of scalar values (not allowed
> in JavaScript).
Yes, mutating an object parameter is also something to be avoided. It's worse when these mutations are spread across your application. This is related to your earlier point about OOP:
OOP promoted a better alternative by controlling where the mutations occurred: as part of the objects themselves. If mutability and side-effects can't be avoided they can at least be controlled in a more disciplined manner. Bertrand Meyer took this further by defining the Command–query separation principle:
<https://en.wikipedia.org/wiki/Command%E2%80%93query_separation>
"every method should either be a command that performs an action, or a query that returns data to the caller, but not both. "
out parameters violate this. The caller is not necessarily the one with the parameter target defined, it could have been threaded from elsewhere.
And to the later point:
"asking a question should not change the answer"
out parameters violate this as well:
``C#
void Modify(int x, out int result)
{
result = x * 2;
}
int x = 2;
Modify(x,out x);
Console.WriteLine(x); // value is now 4
Modify(x,out x);
Modify(x,out x);
Console.WriteLine(x); // value is now 16
```
Let's return to your issue about parsing numbers. Compare:
```C#
string input = "whatever";
double result;
if(double.TryParse(input, out result)) {
// whatever
} else {
// whatever
}
```
vs.
```JS
let input = "whatever",
result = parseFloat(input);
if(isFinite(result)) {
// whatever
} else {
// whatever
}
```
What are you really gaining with the out parameter here?
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2021-03-20 13:07 -0700 |
| Message-ID | <ef201af1-f77e-483d-b34e-599db6e1e807n@googlegroups.com> |
| In reply to | #39723 |
On Saturday, March 20, 2021 at 2:00:01 PM UTC-5, Michael Haufe (TNO) wrote: > Threading mutable state through my program is not a positive thing. It's just as bad as John G. Harris's comment on using an object as the parameter. Mutating a parameter directly, or using it as an additional output mechanism is more complicated by definition: complecting what should be orthogonal features. I'm not implying that John G. Harris is promoting that as a good idea, I'm just using that approach as a reference.
[toc] | [prev] | [next] | [standalone]
| From | John G Harris <niam@jghnorth.org.uk.invalid> |
|---|---|
| Date | 2021-03-20 19:29 +0000 |
| Message-ID | <03jc5ghlc0sd6329k6r189ot7fccf2ie5p@4ax.com> |
| In reply to | #39716 |
On Sat, 20 Mar 2021 14:49:42 +0300, Anton Shepelev <anton.txt@gmail.com> wrote: <snip> >In that sense, OOP is all about such side-effects, where a >method call may change the state of data that is not >explicitly passed to it, but is buried somewhere in `this'. <snip> It seems you haven't realised how useful objects can be. Take a user-defined date object, for instance. You tell it to move on 9 days, it moves on. You don't know how it does that; you only know how to tell it. You ask it which day of the week it is now. Again you don't how it does that; you only know how to ask it. If the language allows a program to be spread over several files then the code for these objects can be in the same file for every project using this language. No copy and paste and no risk of "Oops, I missed part of the code". The biggest problem is learning to ignore the huge amount of metaphysical claptrap that's been written and said about objects and classes. John (PS ECMAScript Date objects don't have a 'move on' method. It's more messy.)
[toc] | [prev] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-20 20:35 +0000 |
| Message-ID | <slrns5cn5b.4lq.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39725 |
On 2021-03-20, John G Harris <niam@jghnorth.org.uk.invalid> wrote: > (PS ECMAScript Date objects don't have a 'move on' method. It's more > messy.) Hah. ECMAScript Date objects have things like date.setMonth(17) which is simultaneously appalling and better than many other languages.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2021-03-15 00:27 +0300 |
| Message-ID | <20210315002732.dbb3221feb6d3a0c065292cf@gmail.com> |
| In reply to | #39628 |
I wrote:
> I started learning JavaScript but yesterday, but am
> already stuck at implementing input/output parameters.
I have come up with what might be called emulated poiters:
// Returns JavaScript for the defintion of a "pointer" to a variable named `v':
// The identifier of the pointer is that of the variable prepended by a $.
function makeref(v)
{ return `var $${v} = {set _(val){${v}=val;},get _() {return ${v};}}`; }
which may be used thus:
// Calcualtes the square root of `value` and puts it into `$root`.
// Returns whether the operation has succeeded.
// In case of an error, stores error message in `$errmsg`.
function sqrt2
( /* in number */ value, /* value to take the root of */
/* out number */ $root , /* "pointer" to result */
/* out string */ $errmsg /* "pointer" to error message */
)
{ if( typeof( value ) !== "number" )
{ $errmsg._ = "value is not a number.";
return false;
}
if( value < 0 )
{ $errmsg._ = "value is negative.";
return false;
}
$root._ = Math.sqrt(value);
return true;
}
function test(v)
{ var /* string */ resmsg;
var /* number */ root ; eval( makeref( "root" ) );
var /* string */ errmsg; eval( makeref( "errmsg" ) );
if( sqrt2(v, $root, $errmsg) ) resmsg = `Success: ${root}`;
else resmsg = `Error: ${errmsg}`;
console.log(`Square root of ${v}: ` + resmsg );
}
test("s" );
test(-5 );
test( 1.44);
This code prints:
Square root of s: Error: value is not a number.
Square root of -5: Error: value is negative.
Square root of 1.44: Success: 1.2
Is it possible to define a "macro" in order to simplify the
compilcated expression:
eval( makeref( "root" ) )
so that it becomes, say, ref("root")?
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | Jon Ribbens <jon+usenet@unequivocal.eu> |
|---|---|
| Date | 2021-03-14 23:51 +0000 |
| Message-ID | <slrns4t8bk.4fd.jon+usenet@raven.unequivocal.eu> |
| In reply to | #39645 |
On 2021-03-14, Anton Shepelev <anton.txt@gmail.com> wrote: > var /* number */ root ; eval( makeref( "root" ) ); > var /* string */ errmsg; eval( makeref( "errmsg" ) ); Bear in mind that using 'eval' is extremely bad for performance. It means the language runtime has to give up on compilation and go back to using a basic interpreter. And, stop trying to fight the language. You will end up with terrible unreadable unmaintainable code.
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.javascript
csiph-web