"Params: Function parameters must be named, but no need to repeat yourself, if the argument is named the same as the parameter (i.e. keyword arguments can be omitted). Inspired by JS object params, and Ruby."
I've grown fairly fond of JS implicitly named object parameters, and I always liked Smalltalk's named(-ish) parameters, and this seems like an interesting compromise. I'm not actually sure how Ruby works in this case? I thought its parameters were fairly normal. Are there other languages that do this?
But in the case of one-parameter functions this seems unnecessary, the function name often makes it clear exactly what the first parameter is. And if you are going to support Subject-Verb-Object phrasing (as suggested later) then the Subject is another implicit parameter that probably doesn't need naming.
Maybe another approach is that all functions take one unnamed argument, and there are structs with named members for any case when that single argument needs to contain more than one value. Which starts to feel like JS/TypeScript. The static typing to support this in TypeScript feels really complex to me (it's unclear if the language described uses static types).
OCaml gets all of this right already. Labels are optional (which is IMO better than the article suggestion). You can abbreviate to only the label if the parameter variable is the same as the label. You can omit the label for labelled parameters if you want, they just become unnamed positional parameters. And of course the main thing is type safety to help you get parameters right in many cases.
The ability to treat named arguments as unnamed is not necessarily a feature - it's too easy for the caller to mistakenly pass the wrong thing without a label, and it also makes it that much harder for the API owner to version it in the future. Python adopted a special syntax for named-only arguments for these reasons.
(For others, labels are optional in three senses: not all parameters need to be labelled, the compiler can emit a warning if a label is omitted but you may want this to be an error instead, and there are optional labelled arguments which may be omitted entirely in some cases. Labels are not optional in that the type system is unwilling to convert between labelled/unlabelled or optional/omitted/required parameters and the compiler mostly won’t add hidden coercions between these types)
A common case where the trivial-value syntactic sugar fails looks like:
foo ~some_descriptive_label:t.some_descriptive_label
bar ~something:!something
Or
baz ~the_option:config.the_option
(Why not just pass the config? Two reasons: it is nice to have the interface being explicit about what data is needed, and the function may come from a module that cannot depend on the definition of the config type.)
I'm surprisingly happy with IntelliJ / Java's behavior. Java is all positional parameters, but anytime the arguments aren't obvious, IntelliJ shows the parameter name with subtle syntax highlighting. It feels like the best of both worlds.
A ton of features on this list really require an IDE or rich program representation, or _something_ that's not just plain text. For instance using content hashes to refer to functions is only reasonable with IDE tooling support.
But programming language itself is a tool. And, you need one tool to improve the other, that imply your tool (programming language) is not good enough.
IMO, the only reason why java is still in use - superb IDE and tooling, that compensate terrible language design.
Vertical alignment. When you press the down arrow, you don't know what position your cursor will land on because it's not visually aligned with the character above. Kind of defeats the purpose of a monospace font (within that one line where it's applied).
> I've grown fairly fond of JS implicitly named object parameters, and I always liked Smalltalk's named(-ish) parameters, and this seems like an interesting compromise. I'm not actually sure how Ruby works in this case? I thought its parameters were fairly normal. Are there other languages that do this?
Ruby allows keyword arguments, which are very similar to object parameters in Javascript:
One thing that's missing in Ruby (that I quite like in JS) is the ability to rename keyword arguments in the named parameter list, like:
// javascript
const example = ({ max: maxNum = 123 }) => {
/* ... */
};
# ruby
def example(max: 123)
max_num = max # can't do this in the parameter list
# ...
end
Honestly, this limitation is just about the only thing I think is missing from Ruby's parameter-list syntax.
> But in the case of one-parameter functions this seems unnecessary, the function name often makes it clear exactly what the first parameter is. And if you are going to support Subject-Verb-Object phrasing (as suggested later) then the Subject is another implicit parameter that probably doesn't need naming.
Maybe there could be a special sigil for positional arguments? I like the idea of gently discouraging them, but still making them possible. Maybe something like
// hypothetical language
function singleArgFunction(@arg0: number) { /* ... */ }
function mixedArgFunction(@arg0: number, foo: string, bar: string) { /* ... */ }
function standardFunction(alfa: number, bravo: string) {/* ... */}
singleArgFunction(0);
mixedArgFunction(1, foo: 'hello', bar: 'world');
standardFunction(alfa: 123, bravo: 'abc');
On your last point I’ve been toying with the idea of having even the function it self folded into that struct
the struct defines the unbound inputs ad well as mapping those to different named outputs
one interesting aspect to play around with is to then have commutative, and associative, application/evaluation operation where structs (or environments really) are merged and evaluated by binding what can be bound
say
(a,b:1+a)(b,a:1,c:a+b,d:2)
would evaluate to
(a:1,b:2,c:3,d:2)
not saying its a good idea - kind of falls down on scoping - bu could be an interesting toy.
This makes me think about some sort of exec-with-dynamic-scope approach to functions, like:
func = {
b = 1 + a
}
result = func {
a = 1
c = a + b
d = 3
}
Where func {...} (two adjacent blocks) is like a composition and merges the two blocks. "=" has the mathematical meaning, not assignment but a statement of equality. The parameters are just the free variables, e.g. func has a parameter of a. Are external routines or functions also parameters? I'm inclined to say yes, and that it's interesting to treat them as such.
This is all very Mathematica/Wolfram-like, with concrete expressions with undefined terms, different than functions that are executed.
The result has no real sense of order, and so it implicitly has to be purely functional. I can imagine using this to build things-that-execute, where this code doesn't execute but defines an execution (like tensorflow). Or there's some outside layer that creates streams of input, and the "execution" is how it responds to those streams. That outside layer is where all the system integration happens. It would work well with React-style unidirectional data flow. But I think for any practical program you'd have to live in both worlds.
The latest Ruby version works as described in the «keyword arguments can be omitted» link.
The dream language is gradually static typed. Like TS, but the type system and inference would ideally be more like OCaml or ReScript. Hopefully avoiding some of the complexity of TS, and gaining more soundness.
"Params: Function parameters must be named, but no need to repeat yourself, if the argument is named the same as the parameter (i.e. keyword arguments can be omitted). Inspired by JS object params, and Ruby."
I've grown fairly fond of JS implicitly named object parameters, and I always liked Smalltalk's named(-ish) parameters, and this seems like an interesting compromise. I'm not actually sure how Ruby works in this case? I thought its parameters were fairly normal. Are there other languages that do this?
But in the case of one-parameter functions this seems unnecessary, the function name often makes it clear exactly what the first parameter is. And if you are going to support Subject-Verb-Object phrasing (as suggested later) then the Subject is another implicit parameter that probably doesn't need naming.
Maybe another approach is that all functions take one unnamed argument, and there are structs with named members for any case when that single argument needs to contain more than one value. Which starts to feel like JS/TypeScript. The static typing to support this in TypeScript feels really complex to me (it's unclear if the language described uses static types).