12 ms·
Named arguments are coming in PHP 8
- segmondy 6y agoPHP will eventually evolve into Java. The only difference will be the runtime.
- hprotagonist 6y agoin python i started writing any function that takes >2 arguments as either def foo(*,a,b,c)... or def foo(obvious_and_required_thing, *, a,b,c) ... and noticed an immediate improvement in clarity.
- nafey 6y agoWhat does * represent here? The "self" object?
- masklinn 6y agoIt‘s a separator between positional and keywords. It’s * because the “rest” argument (*args) also makes following arguments keyword-only, so a lone star is essentially one which collects nothing.
- foota 6y agoSo this requires the following args to be named? Neat!
- masklinn 6y agoYes. For python-level functions initially all arguments could be passed either positionally or by keyword, unless they slotted into the special `∗args` (positional-only) or `∗∗kwargs` (keyword-only) parameters (note: the star-prefixes is the important part here the names can be anything). Now I'm saying this was for python-level functions because (AFAIK) at the C level it was always possible to rather easily define positional-only or keyword-only arguments. Anyway one of the improvements of Python 3 was to allow parameters other than `∗∗kwargs` after `∗args`, with the effect of making them individually named but keyword-only (PEP 3102). A logical extension of the same was to allow keyword-only arguments without any positional, that's what the `*` pseudo-argument defines: > The reasoning behind this change is as follows. Imagine for a moment a function which takes several positional arguments, as well as a keyword argument. > Now, suppose you wanted to have 'key' be a keyword-only argument. Under the above syntax, you could accomplish this by adding a varargs (nb: `∗ignore`) argument immediately before the keyword argument. > Unfortunately, the 'ignore' argument will also suck up any erroneous positional arguments that may have been supplied by the caller. Given that we'd prefer any unwanted arguments to raise an error, we could do this (nb: add an explicit assertion that `ignore` is empty) > As a convenient shortcut, we can simply omit the 'ignore' name, meaning 'don't allow any positional arguments beyond this point'.
- sdoering 6y agoThank you very much. I am using python for some time now. Stumbled upon this, but never took the time to read up on it. If anybody also wants to know more I found this extensive post explaining the concepts behind * and in python (not in multiplication): https://treyhunner.com/2018/10/asterisks-in-python-what-they-are-and-how-to-use-them/ https://treyhunner.com/2018/10/asterisks-in-python-what-they...
- throwaway43234 6y agoI understand that this is standard practice by now, but this is one of those cases where I can't help but feel the language design team strayed too far from the original spirit of python. Now there's yet another possible interpretation of an asterisk: multiplication; splatting; exponentiation; declaring variadic arguments; and now declaring that all subsequently declared arguments are to be keyword-only. And I understand that it sort-of relates to declaring variadic arguments, but it certainly isn't declaring variadic arguments, and in my opinion reusing the same token in the same syntactic construct for two wildly different purposes is destined to cause confusion. For evidence, see the other replies: people don't know about this and can't easily tell what it does. This runs counter to the Zen: "Readability counts", "Explicit is better than implicit", "Special cases aren't special enough to break the rules.", etc. I think JavaScript got this right where the semantic resolution steps of arguments pretty closely follow the steps for assignment, which means once someone understands the basic idea of object destructuring they get named arguments for free, in the form of destructured object parameters: const foo = (positionalArg1, {namedArg1, namedArg2 = 'foo'}) => { ... } foo(1, {namedArg: 'bar'}) // resolved same as const [positionalArg1, {namedArg, namedArg2 = 'foo'}] = [1, {namedArg: 'bar'}]
- kabacha 6y agoI'll disagree with you here. In Python `*` is already a extremely popular symbol for expanding and there's no usage conflict between expand and numeric multiplication. This change gels really nicely with the rest of expand ecosystem. I think it's much more beautiful and convenient than your JS example which in all honesty looks necessary cluttered and ugly.
- jakear 6y agoBut there’s no expanding happening here? So why take a token that’s immediately recognizable as either “expanding” or “muliplying-ish” and extend it to mean “or enforcing named parameters and not expanding”? > cluttered and ugly I won’t argue with you about visuals because I don’t think they’re all that important. But, I think it’s undeniable that reusing the same syntactic concepts across different semantic use cases is quite a lot more logically clean & beautiful than introducing new syntax that other HN commenters with past python experience can’t even understand. If someone sees the JS named parameter syntax at a declaration and has any JS experience, they’ll almost certainly figure out what to do - if someone sees the asterisk, even with Python experience, they’ll think “what the heck is this asterisk?” And again, the other commenters on this thread are clear evidence that this is indeed as unintuitive as I describe.
- cheez 6y agome likey
- thaumaturgy 6y agoI'm ambivalent. There's a tension in PHP-land between PHP's roots as a low-ish level, get-it-done, hackish language, with its big standard library and simple scalar types, and the better-organized and quite vocal developers who want it to be more Java-like, with great big frameworks and many deeply-nested complex class hierarchies. Instead of unwieldy hobbyist-hacker balls of mud, you build enterprise-scale balls of mud. Named arguments don't do a lot for the first group. It looks like the big point in favor is not having to look up a reference for which-arguments-go-where in functions anymore, but a good IDE already does that for you. But there is a common anti-pattern where you have some polymorphic function or interface, and you want to accrete your arguments somewhere and then bundle them up and call the function, so then you see things like [1]: call_user_func($function, ['length' => $n, 'foo' => $bar, ...]); ...and that is bad because it totally bypasses all of PHP's type-checking and leaves it up to the called function to sanity-check the input types instead of letting the compiler do it, and basically nobody does that anyway. So named parameters would fix that at least, which would be nice. I'm just not looking forward to the impact this is going to have on code readability, because everyone (including this article) is going to go, "oh, now my parameter list is too long!", and break the function signature into one-line-per-parameter, which is vile. [1]: I'm guilty of this too.
- Aeolun 6y ago> break the function signature into one-line-per-parameter, which is vile Speak for yourself. If each line indicates what it is the parameter for I couldn’t care less. Nobody will use this for functions that have just two parameters. It’s the ones that have 10 possibilities that are crazy.
- zerocrates 6y agoI get why it's being done that way, but the bit about parameter names being allowed to vary in subclasses feels... non-great. As a result you can't really safely use named parameters on calls without more extensive control of what you're being passed: even if you typehint to a class or interface, you can just get passed a parameter-name-changed subclass that breaks your call anyway. Feels like a "strict" type warning would be in order rather than just silent acceptance of the variance combined with a hard error.
- masklinn 6y ago> I get why it's being done that way, but the bit about parameter names being allowed to vary in subclasses feels... non-great. As justified, it feels necessary for backwards-compatibility reasons since named arguments are not defined as named, just used as such.
- zerocrates 6y agoStill feels like a "strict warning" situation. Again, I can see why they have to do it that way because this was just not previously part of the public interface to a function, but it is now, so there should be some indication that doing this name mixing is, in fact, Now A Problem. I guess it can just be handled on a static analysis/code-checker kind of level, but the language already has a system for emitting these kind of "code standards" warnings.
- richthegeek 6y agoThat's always been the way with PHP. It's always been the language of "you _can_ write nice code, but only if you follow strict rules and avoid this (long) list of bad practices that it encourages". > Doctor, it hurts when I bend my elbow like this! > So don't bend your elbow like that.
- mokanfar 6y agoIt's beginning to look a lot like -- typescript
- The_rationalist 6y agogenerally yes, but specifically here typescript does not have named parameters (yeah you can emulate with a hack through object literals which is sad)
- chmod775 6y agoWhat's sad about it? Having interfaces defining the arguments of functions with complex parameters in a type safe manner and with support for auto-completion is one of the greatest thing to ever happen to JavaScript in my opinion. And you get named function arguments as a by-product of something way more powerful than just that.
- ThomWilhelm3 6y agoI always wonder why PHP never seems to favour making breaking changes to keep things cleaner, if you aren't going to improve language constructs in a major version, when will they be cleaned up?
- tonyedgecombe 6y agoI think that post Python 3 nobody is going to do that. It would be interesting to see a fork which removed all the crud though. Something that was easy to use for the person doing occaisional web work or beginner but without the traps and pitfalls.
- echelon 6y agoPython 3 attempted too much change at once. The Python folks could have spread incremental rollout of the changes across several major version numbers and probably not have faced such slow adoption.
- tonyedgecombe 6y agoI thought the problem was carrying on support for 2.xx too long. Some people will never move on unless they are forced to.
- mrweasel 6y agoI'm not sure that they could have spread it out. I believe that was the point of Python 3. Still, PHP may end up in the exact same position Python was in for the last decade, if they tried to do a similar change. It could be worse of cause, they could end up like Perl 6 (now Raku), which makes Python 3 look like a successful transition in comparison.
- pansa2 6y ago> Python 3 attempted too much change at once. Python 3 got this so, so wrong. It changed enough to break everyone's code, but not enough to make upgrading worthwhile. It could have changed more, or changed less - done right, either would have been better than what actually happened.
- slifin 6y agoThe fact it errors if you over supply the function arguments is a bit worrying Adding a key to an array shouldn't be a breaking change, if you over supply a function by position today PHP doesn't error
- deleted 6y ago[deleted]
- Denvercoder9 6y ago> if you over supply a function by position today PHP doesn't error I'd argue that this it the worrying part. How often do you intentionally supply an extra argument, and how often is it an accident? I'd take the warning.
- slifin 6y agoIt's important to recognise what we can't do with that error in: <?php $user = [ 'age' => 25, 'name' => 'Brent', 'email' => 'brent@stitcher.io', ]; function send_email(string $name, string $email) : void { //... } send_email(...$user); ^So this would error, even though it's a nice specification as far as the function is concerned, I'm all for strict static analysis but not at the expense of open maps "If your program deals with information, these are among your primary problems: information is sparse, incrementally accumulated, open/extensible, conditionally available, formed into arbitrary sets in different contexts, merged with other information etc."
- Denvercoder9 6y agoWhile you're right, I don't think that's something commonly used. I definitely can't remember the last time I wrote code where this would be useful. That might be because usage of associative arrays is more or less discouraged in modern PHP in favor of value objects (especially with property promotion in PHP8). Main reason for that is that this usage is horrible for IDEs and static analysis. Way too easy to rename a parameter and create a runtime error. Typing is also enforced at usage instead of creation, and you have to repeat the type information in every function signature.
- thinkindie 6y agoI really love this new feature however my only concern is that renaming some parameters will trigger a lot of changes in other places as a side effect, thus polluting diffs.
- stinos 6y agoI get what you mean, but I remember at one point going through some kind of 'oh no, it's a large diff' or even 'do not do this because the diff will increase' phase. And I realized that's just not ok. There's already enough things to keep in mind when programming, adding an extra one just because some external tool which actually doesn't have a lot to do with how the code works, i.e. holding back changes because of diff, just isn't worth it. Now, I admit cluttered diffs can be a problem, but there are workarounds: more fine-grained commits (especially separate commits for renames only) and better diff display. As an example of the latter: another commnter mentions one argument per line produces better diffs. It does for your standard display with +++/---, but tools like Sublime Merge have this covered and siplay the change in such a way you can immediately see what argument changed it's name, inline in the code. If it's was just a typo fix it will usually only highlight the changed character(s) not the complete name. Even going from all arguments on one line to one agrgument per line is covered, since it'll just display it as added whitespace and won't highlight the argument themselves indiacting they did not change.
- majewsky 6y agoMy biggest pet peeve is when I meticulously craft a feature branch with commits neatly separated by subtopic so that it's pleasant to review... and then the reviewer just takes a glance, writes "lgtm" and squash-merges.
- matsemann 6y agoNot sure if the standard library has evolved since my PHP days, but this would at least solve the "key / haystack" issue. In which lots of the standard library had different orders in which parameters are passed. One can finally pass them named and no longer have to care about the order. This may also have been solved by better tooling since then, though.
- disiplus 6y agoa proper IDE solves that, but i always laugh when getting back to php why they made array_map and array_filter switch parameter order.
- Denvercoder9 6y ago> why they made array_map and array_filter switch parameter order It kind of makes sense if you look at the signatures (array_map takes a callable and a variable number of arrays, while array_filter takes a singe array and an optional calable), but yeah, it's horrible to use.
- jonplackett 6y agoThis was my favourite thing about learning Swift. I hadn’t used a named argument language before. It feels very relaxing knowing that the compiler can check all these things for you. I haven’t used php for years but it’s cool to see it adopting this. Maybe I’ll give it another go!
- DaiPlusPlus 6y agoC# has had named arguments for a while now too - and I’m in love with them. They’ve helped me avoid many ugly bugs caused by refactoring, such as when a method has many parameters with the same type - and a refactoring reordered or added/deleted parameters - thanks to named-parameters the call-sites still worked instead of silently failing (because the call-site would still be type-correct and compiled, even if it was intent-incorrect). My only peeve is that VS still doesn’t let you style/colour named-argument labels in a different colour, so it does add to visual-noise in the editor. Adding labels to every argument is just silly, so I do have a personal hard-and-fast rule that any call-site of a method with literal arguments must be explicitly labelled (especially booleans!), and any call-site of a method with consecutive homogenous typed parameters must also be labelled - these rules have worked out fantastically for me.
- iomcr 6y agoDefinitely a top feature of crystal lang. Not having to worry about what the default was to the second positional argument while using the third is satisfying, not to mention that it's basically optional self documenting, too.
- skocznymroczny 6y agoNamed arguments is a no-brainer for me for any kind of programming language. I am hoping D adopts named arguments too, although it's a very uphill battle there with many programmers coming from C/C++ background being opposed to it in the name of API stability.
- raxxorrax 6y agoI agree, it is a sensible improvement. What I don't like is spread operators in every form, but I can certainly live without funcy(null, null, null, null, null, null, cake, null, lie)...
- spaetzleesser 6y agoI remember when dealing with Excel COM having lists of 30 arguments and more. And it made a difference if parameter 26 or parameter 27 was null.
- stunt 6y agoNamed arguments are great where you can't do it without them. It's good that language provides you the tool. And it's your job to as a developer to not abuse it.
- perlgeek 6y agoTwo of the languages I use most often (Python and Raku (formerly known as Perl 6)) have named arguments, and it improves clarity of code tremendously. I don't know how well it fits into PHP, but if it's anything like in python or raku, go for it! :-)
- deleted 6y ago[deleted]
- chx 6y agoThere was a time when I would've been all-out in favor for this because one of the most often used functions in Drupal had no less than seven arguments: https://api.drupal.org/api/drupal/includes%21common.inc/function/l/5.x https://api.drupal.org/api/drupal/includes%21common.inc/func... it being seven, the running joke was knowing the Seven Parameters Of L is our initiation rite. Then the options collapsed into an array https://api.drupal.org/api/drupal/includes%21common.inc/function/l/6.x https://api.drupal.org/api/drupal/includes%21common.inc/func... and that was in 2008. And then URLs in 2015 became a value object and while you can still pass absolute => TRUE in options if you really want to, you can just call setAbsolute() on the object. I guess if PHP core adopts this , phpstorm will quickly adopt as well and typing strpos( will immediately expand to strpos(haystack: , needle: so you can just fill that in. I guess? so maybe a reluctant yes but I am a bit wary of the APIs that will follow from this. I guess I have slowly grown fond of value objects? I must be getting old.
- The_rationalist 6y agoUltimately every high level languages are converging to have the feature set of Kotlin, its nice to see them getting closer and closer.
- rbanffy 6y agoPython has it since ever.
- sanxiyn 6y agoCommon Lisp had it earlier.
- rbanffy 6y agoCommon Lisp had everything before every other language.
- The_rationalist 6y agoI'm talking about features in general, not just named parameters. Python doesn't have an advanced type system and yes I'm aware of mypy
- nurettin 6y agoThere are a lot of arguments surrounding this subject. Just came in here to chime about how I miss named arguments in c++. Sure, I can emulate them [0] but at the cost of ide support, runtime and compile time. https://github.com/nurettin/pwned/blob/770144a15efe7ab96bf4d0414bcaf7424e9a9118/parameters/tests.cpp#L15 https://github.com/nurettin/pwned/blob/770144a15efe7ab96bf4d...
- cma 6y agoThey are effectively in C++20 without real penalty (designated initializers).
- nurettin 6y agoYes, designated initializers help initialize a dto, much like what C# did back in 3.0 times. I wish they did something similar to function parameters so we didn't even have to create a data transfer object.
- cletus 6y agoSo here's a good test for the value of [language feature X]: Do people naturally try and reinvent that feature in its absence? So for named parameters you have: 1. Javascript would often be written with methods with a single "options" parameter, where "options" is an anonymous object and basically a map; 2. Day-to-day I write Hack. Many functions are similarly written taking a shape as an argument. Shapes are structs, basically, but the typechecker is smart enough to treat them as a well-defined by anonymous type. 3. I've also seen C code that does much the same with things structs. Empirically there seems to generally be a demand for this kind of feature and it makes sense: long parameter lists are tedious and error-prone (have you ever seen a function that has 3 boolean parameters in a row?) where people try and be helpful by providing "optional" parameters (which are really just parameters with default values). So sure, I'm all for named parameters.
- noir_lord 6y agoThree? I found one in work codebase that had 9. That's 2^9 states to consider.
- hajile 6y agoJS records are superior. I can create an object, then dynamically add various parameters before sending them rather than bogging down the function call. Destructuring in particular ensures this is pleasant for both the function creator and consumer. You see a similar debate between StandardML and Ocaml though on a more fundamental level. SML uses structurally-typed records, so you can instantiate an inline record without needing to add any types and the function will destructure it for use. Ocaml went with nominal typing making this painful, so they added a complex optional argument syntax instead. Typescript is also structurally typed and I'd guess this is the reason.
- quattrofan 6y ago"a significant impact on my day-to-day programming life"...seriously, what a bunch of shite
- romanovcode 6y agoExactly! Who the hell programs in PHP anymore.
- thrownaway954 6y agoevery wordpress, mangento and laravel developer which probably make up about 80% of the websites on the net. wordpress alone counts for 64% of the websites out there. https://w3techs.com/technologies/details/cm-wordpress https://w3techs.com/technologies/details/cm-wordpress
- hnarn 6y ago> named arguments allow you to pass input data into a function, based on their argument name instead of the argument order Granted, I'm not a PHP developer, but I can't understand why a change like this would be controversial. It sounds like it's optional, and would help greatly to reduce mistakes when passing arguments to functions? Having multiple lines of things being passed to a function may look odd to some, but couldn't the same argument be made as with arrays, that one line per "thing" makes sense, if nothing else to clean up diffs when collaborating on code?
- userbinator 6y agoGranted, I'm not a PHP developer, but I can't understand why a change like this would be controversial. It sounds like it's optional, It's only optional when you're writing code. Even if you don't use features in your own projects you're undoubtedly going to be reading a lot of other's code, which may or may not use these features, and from that perspective added language complexity is a burden.
- chriswarbo 6y agoAny framework/library code which abstracts over invoking a callable must also be extended to support associative arrays, and to avoid assuming that parameters will be given in the order they're defined. For example, things which play around with call_user_func and func_get_args (e.g. delayed evaluation, partial evaluation, currying, mapping over datastructures, composing/pipelining, etc.)
- hnarn 6y agoSure, but it's only confusing when reading it if it's hard to implicitly sort of understand what's happening when you're not used to it, right? Named arguments seem pretty straightforward to me, in the sense that it's relatively obvious what they are when you see them. It's not exactly like a new operator or some kind of symbol unique to the language that is almost impossible to understand without looking it up.
- mkopinsky 6y agoIt's optional for the caller, but not for the callee. I think the controversy centers around two things: a) Specific to this feature: For library maintainers, this means that argument names are now part of the public API, whether I like it or not, and renaming a parameter from $orderBy to $sortBy is now technically a breaking change. Yeah, you can put something in the readme saying "Heads up: I don't support named arguments and intend to rename arguments in semver-minor releases", but should you need to do that? b) General to all new PHP features: PHP is a great language, with lots of crap code written in it. Will this feature result in people writing better or worse code? Just because something is optional doesn't mean it's a good idea, if it will result in the overall code quality of the ecosystem to get worse. Some people think that named arguments will make it too easy to create monster functions with too many parameters. I personally support (aka am DELIGHTED by) named arguments, but I'm sympathetic to the concerns of library maintainers and I don't see a better way around it than a remark in the readme (at least until/unless they introduce e.g. a @@NoNamedArguments annotation in PHP 8.1). And I think that the benefits of named arguments far surpass the risk that they encourage people to create methods with too many arguments. But I can see both arguments.
- deleted 6y ago[deleted]
- conradfr 6y agoI've often wondered why there was no "default" keyword, so you could call a function like this: foo('first arg', default, 'third arg'); Named parameters will do but they are more verbose. Speaking whishes, method overloading would be great.
- manyxcxi 6y agoHaving switched from 80% Java (20% about 5 other languages) to probably 75% Kotlin over the last year, one of my absolute favorite things named arguments. When you name your arguments, simply supplying them will use the default if one has been specified. If one hasn’t been specified then you must provide it when calling and your compiler/IDE will definitely let you know. I used to go out of my way with method overloads, JavaDocs, argument @annotations, and Builder classes in order to get this same level conciseness and cleanliness in my Java code. It is extra work (even with Lombok) but I personally can’t stand when I don’t keep it clean like that. Understandably a lot of other developers on my teams don’t always go to the same lengths. I honestly haven’t ready the details on PHP’s plan for this, but with Kotlin’s names arguments I’ve found almost no need of method overloading anymore- most of those input variations are now covered (except for when you’ve got different types coming in, which usually can be handled with a common interface or base class).
- conradfr 6y agoYeah I'm totally fine with named arguments, I even thought they would come sooner (I've been doing PHP since 1998 so I have some perspective ahah). And yes overloading is more about different types for me. I guess I got accustomed to it with C# and nowadays Elixir. PHP 8 has union types so I guess it will do.
- crazygringo 6y agoI'm so happy to see named parameters become more common. They're absolutely critical to writing code that is easy to read. The name of a function tells you what it does, arguments equally need names to tell you what they do. Even if I have a great IDE, I don't want to hover/cursor over the line to see what each argument does, each random "0" or "null" or "1" or whatever. There are also plenty of times I'm viewing code that isn't in an IDE, like a diff. Obviously they're not always needed, like in functions that take only one or two required obvious parameters. But otherwise, they can make the intent of a line of code obvious at a glance, and are a huge step toward making code self-documenting. I just can't believe this is a change that's only picking up now, rather than 20 years ago.
- linux2647 6y agoOn the other hands, many JetBrains IDEs will insert the names of parameters in a function call inline to help identify what passed variable belongs to which parameter. It’s not inserting it in the actual source code, but exists purely in the UI (https://www.jetbrains.com/help/clion/parameter-hints.html https://www.jetbrains.com/help/clion/parameter-hints.html). It’s useful if $LANG doesn’t have named parameters
- DeusExMachina 6y agoIt's pretty funny that named arguments were, for a long time, a feature present only in Objective-C of all the languages I tried (and I tried many). It was one of the features of Objective-C I liked and I missed in any other language. I also think they were one of the reasons many developers disliked the language. When Swift was introduced, it got named parameters from Objective-C and now they are getting more "mainstream", entering in a language much more widespread than the former two.
- moloch 6y agoPython has had named arguments for a long time (since v1.4), which is arguably more widespread than PHP or Swift.
- Yoofie 6y agoWhen I was learning Verilog HDL, named parameters are commonly used and highly encouraged. I wondered why more traditional programming languages didn't use this concept aswell for the same reasons the article goes into.
- nobleach 6y agoI first ran into them in Python myself. After using kwargs for the first time, I wondered the same thing. While I try to limit the number of args I pass to functions and methods, sometimes it simply can't be helped. Kotlin is a wonderful example of how both positional AND named arguments can be supported.
- gremlinsinc 6y agoIt feels like an anti-pattern, but I've been burned so many times by forgetting what order things go in, and not wanting to waste the 10 seconds to go look, that in a lot of methods if I have more than 2 parameters, I'll convert it to an array. the associative array, thus giving me the named attributes. It's a bit hackety, but the new named params looks like a much more elegant solution. One issue also is if you have a method that takes 3 arguments and the 2nd is an integer not a string, and you pass a string you'll get an error... using an array, you can just test if the array key exists or not, and skip functionality as dictates by what's passed in.