Adam Cameron
https://i2.paste.pics/84ae311855506da886f46722ed3b48fb.png▾
Mark Takata (Adobe)
05/06/2022, 9:41 PMAdam Cameron
deactivateduser
05/07/2022, 12:32 AMaliaspooryorik
Adam Cameron
...
operation.
I cannot see a way that there's any ambiguity either. It's 100% "match the named ones, pass all others in the rest param.
What happens if the method call actually specifies a named argument that matched the name of the "rest" param? Same as if one specifies a positional argument in the position of the "rest" param: it doesn't matter. all arguments that don't match other named params are passed in the rest argument value.
I also think that if for some reason named arguments are not supported for use on function using the rest operator, then an exception should be thrown; not simply the code being ignored.
And whatever the behaviour is needs to be documented.Adam Cameron
deactivateduser
05/08/2022, 8:40 AMAdam Cameron
I suppose that the language could treat the variables differently and categorize the arguments as if …rest then collect all unnamed variables else fall back on normal argument pass throughWell: exactly. This is how the rest operator works. It won't come as a surprise to anyone.
function f(param1, param2, param3)
With ordered or named arguments: the behaviour is the same. All args (any number of them) passed go into their own slots (either index or name).
function f(param1, param2, ...param3)
With ordered or named arguments: the behaviour is the same. First two args go with their position / name. Rest go... in the third one. The hint is in the name: rest
operator. There is no ambiguity here.
I also am not a fan of the rest argument being different typesAbsolutely. And that's controlled by the method signature:
function f(required string param1, required numeric param2, ... date param3) // does not work in CF2021. Does not error, but ignores the rest operator
I need to call that method thus:
f(param1="a string", param2=42, [any other named params you like but they need to be dates])
// or
f(arg3=needsToBeADate, arg3=alsoNeedsToBeADate, anyOtherArg=yupADate, param1="a string", param2=42)
It is also a code design decision. Not a language design one. And the intent is absolutely clear from the method signature.
Seems like a very big break in encapsulation.That comment doesn't make any sense to me. ----
I have a feeling it is going to be a backward compatibility thing. Since named parameters can be passed through and the function have full access to them, how does one know wether it should be passed through or collected?Because the method signature would specify the rest operator. You seem to think there some sort of magic going on to invoke this behaviour. The method literally needs to specify
...lastParam)
in the method signature.
Or do you mean ppl that have taken a method like this:
function f(this, that, ...everythingElse)
And call it like this:
result = f(this="something", that="something else", thing="whatevs", sigh="ridiculous")
And just ignore the fact they were the ones who put the rest operator in the method signature in the first place, and the implementation of the method is intrinsically expecting all the rest of the args to be collected into one data structure_?_ You're suggesting this is actually a thing that would happen? You would have to implement a method actively specifying the rest operator and then explicitly implement the method to ignore it. Who would do that?
Or let's say it's a third-party method that says something like:
/**
@this - this thing
@that - that other thing
@everythingElse - everything else gets treated as an array
*/
function f(this, that, ...everythingElse)
And then some Fuckknuckle comes along and calls it like this:
result = f(this="something", that="something else", thing="whatevs", sigh="ridiculous")
And expect to not collect {thing="whatevs", sigh="ridiculous"}
into the everythingElse
param value? Despite the docs and the method signature (and, intrinsically: the implementation) saying that's what it does. How would this come about?
The mooted change here is to fix methods than use the rest operator so the methods internal logic can be implemented as needs must for named args. It doesn't impact the consuming code in any meaningful way. No method using the rest operator can currently support being called with named arguments. It doesn't work (see also: this entire conversation). So there's no backwards compat issues. Fixing it would change behaviour from "it doesn't work" to "it does work".deactivateduser
05/08/2022, 6:20 PMfunction(regarg, collected1,collected2)
I would get an arguments scope with a single key of regarg, and then an array of arguments in the rest key. But if I call it as function(regarg=regarg, collected1=collected1,collected2=collected2)
I would get a single key with the regarg like the first but then I would get a struct (maybe an ordered struct assuming the name argument parsing parse/Lexing can maintain the order) as the second argument. So you have to write your function to handle both because you can't predict how developers will use the function.deactivateduser
05/08/2022, 6:29 PMAdam Cameron
So you have to write your function to handle both because you can't predict how developers will use the function.This is a good point that I had not thought about. I suspect it would probably be solved by gathering them as a
coldfusion.runtime.ArgumentCollection
though (same type used for the arguments scope). This can be accessed via either index or key name. I think this is inkeeping with idiomatic CFML? It'd be transparent to most CFML devs ("It'd just work", and it would never occur to them to wonder why/how), and would not be "surprising" to users that are perhaps a bit more... discerning.
I'd honestly rather have the half ass implemented …rest feature removed or left as order parameter only then risk the fundamental change to how parameters are written and see more issues arise.I'd prefer they threw an exception with named args and said "not supported", that just ignore it. Code should not be ignored. This also circles back you your - valid - point I quoted above... the dev currently kinda has to manually check if the function's been called as they would be intending (positional args) or by some twerp using named params.
deactivateduser
05/09/2022, 5:44 PMAdam Cameron
your still assuming order in the named parametersThat is already the case with named arguments and how they're exposed in the
ArgumentCollection
anyhow. It's no different from how it works now. This is what I see is the benefit of taking this approach: it's already well-trod and well-understood ground.deactivateduser
05/09/2022, 5:54 PMAdam Cameron
deactivateduser
05/09/2022, 6:01 PMdeactivateduser
05/09/2022, 6:03 PMWhen the function signature doesn't specify a nameThen why do we need to collect it since the argument scope is already a collected set.
deactivateduser
05/09/2022, 6:14 PMAdam Cameron
Is there ever a safe way to inform the developer who only gets the signature of your function, what named parameters to use in case they have fusebox or some other framework/factory that always uses named parameters?Sorry, I'm not gonna get into dumb whataboutery like this. The same could be said of any function where the dev "only gets the signature of your function". "without docs, isn't it hard to work out how things work". Well... yes. [boggle] The thing is... variadic functions are really well-trod ground. This is not something Adobe invented. Everything you say above (immediately above, and a bunch of stuff in earlier comments, back when I had more patience) applies equally to the implementation of variadic functions in CFML without the rest operator. What we're trying to do here... given Adobe have decided to formalise syntax for variadic functions... is to work out how to implement them, and assess the shortcomings therein. Given they've done a half-arsed, unthinking job of it so far. Yer arguing the merits of variadic functions at all. I mean... fill yer boots... it's a discussion that someone might find has merit. But that's not what this thread is supposed to be about. (and in case you can't tell... I'm beginning to find it a bit exasperating and distracting)
deactivateduser
05/09/2022, 6:27 PMAdam Cameron
function inDiv(message, status) {
writeOutput("<div class="#status#>")
writeOutput(message)
writeOutput("</div")
}
And I realised I need to chuck more attributes on that div, and on whim I thought "let's see how the rest operator will help me here", thinking I could do this sort of thing:
function inDiv(message, status, ...divAttributes) {
attrs = structReduce(divAttributes, (attrs, attr, value) => '#attrs# #attr#="#value#"', "")
writeOutput("<div class="#status# #attrs#>")
writeOutput(message)
writeOutput("</div")
}
And call it thus:
inDiv(message="Cool", status="OK", style="fancy", id="something", whatevs="can't remember now")
TBH I would be more likely to just make divAttributes
a vanilla struct arg, but that's less interesting that trying new stuff. Plus also "oh I wonder how that would work?" is a reasonable question for someone wanting to improve themselves, I think.Adam Cameron
function f(first, ...rest){
writeDump(arguments) // [1,3,4]
}
f(first=1, rest=2, rest=3, other=4)
Which might've been a reasonable approach for the rest operator to worked with named arguments. But: no, didn't work