It's pretty similar to what PHP provides here, except that PHP uses "$this->propname =" and C# uses "field =".
Edit: As someone involved in the RFC, it's somewhat funny, because we considered a special variable like "$field" or "$value" too magic, and C# does just that with a field keyword.
I think it being a keyword does change how magic the feature feels. "$field" and "$this->name" make me think that this behavior is playing by the normal rules of the language but is implemented using some trickery to edit the local scope of this function to add or modify variables. When it's a keyword it says this is a special form and that this is a feature of the language itself.
The `field` keyword also already existed in C#, to add attributes to the backing field of automatic properties, so I think the argument was easier there.
I used it in Unity projects to have serialized/inspectable values exposed through properties:
[field: SerializeField]
public int MyProperty { get; private set; }
readonly is rather a misnomer for "writeonce" in PHP. And as such it also disallows repeated assignment in class scope, while private(set) has no such restriction.
array_find parameter ordering is modeled after other non-variadic array functions, e.g. array_filter also having ($array, $callback) order.
But I agree, there is already some inconsistency, and when adding a new function you have to choose which function to make it consistent and which one to make it inconsistent with.
One of the main advantages of actually allowing more arguments is forward compatibility:
You can, within a library, provide an additional argument to a callback without actually introducing a BC break for all users.
My favorite approach would be allowing too many args on dynamic calls (closures, and function calls with dynamic name, not method calls in general) and otherwise rejecting it.
There's no need to have this in the language just to solve the case you describe.
"function current_thing(id: Int, callback: Fn(Int)) {}" and, when you decide you need more you have a myriad of options to add these. From the despised "function current_real_thing(id: Ind, success_callback: Fn(Int), error_callback: Fn(Error)) {}" to "some_namespace:current_thing(...)" via "OtherClass::current_thing(...)" to "load current_thing from NewImplementationOfThing" and so on.
Being strict and explicit isn't opposed to being flexible. And strictness and explicitness is most often a predicament to allow for future change, rather than hampering that future change.
It's far easier to refactor, maintain, test and reason about strict and limited implementations than to do so with dynamic, runtime-magically-changing implementations.
I found this approach works best with languages having method overloading. For PHP it felt quite limiting, and it also requires you to have more complexity and overhead with wrapping.
But I have no hard evidence at hand, only how I experienced that in PHP.
It's pretty similar to what PHP provides here, except that PHP uses "$this->propname =" and C# uses "field =".
Edit: As someone involved in the RFC, it's somewhat funny, because we considered a special variable like "$field" or "$value" too magic, and C# does just that with a field keyword.