7 ms·
Why not allow function literals that define multiple arity implementations? Something like... def sum(list) do plus = { fn -> 0 end ;
by jakear 3y ago
Why not allow function literals that define multiple arity implementations? Something like...
def sum(list) do
plus = {
fn -> 0 end ;
fn x, y -> x + y end }
Enum.reduce(list, plus(), fn x, y -> plus(x, y) end)
end
Also throwback to when I decided to rant about Elixir for some reason 6 years ago, with the final comment:
Converting a Module Function to a First class function (&Math.square/1):
Why do you make me lose the ability to use Elixir's admittedly powerful Pattern matching on arity feature?"
https://gist.github.com/JacksonKearl/57b617de38b1c647ec414049591b3844 https://gist.github.com/JacksonKearl/57b617de38b1c647ec41404...
- nesarkvechnep 3y agoDid you actually read the article?
- jakear 3y agoDid you read the HN guidelines for commenting?
- giraffe_lady 3y agoHopefully when the entire article is an answer to exactly the question you're asking in the comments there is a little leeway.
- jakear 3y agoSee the comments in other threads where an actual topic of contention was presented and accordingly follow up discussions could be had. The reason for the HN Guidelines is to foster good conversation. "Did you read the article" doesn't.
- giraffe_lady 3y agoThe followup discussion of the author just summarizing the article for you? Ok.
- jakear 3y agoThat's all you've been able to comprehend from reading this thread? Surprising. I'd tell you to get off your high horse, but it seems to be your identity. To summarize: the only reason presented not to do what I said is dubious claims about perf, which were not mentioned in the article whatsoever.
- nesarkvechnep 3y agoThe language is OSS, go fix it. Apparently you have the attitude of someone who knows how.
- jakear 3y agoDang was right, these comments do attract that absolute lowest tier of discussion.
- throwawaymaths 3y agoIf you look at how anonymous functions are compiled at a low level you'll understand why that's not possible: a function is literally "the module it's in" + the bytecode "line number" + arity (so that it knows how many register items to instantiate). For inlined anonymous functions, a secret private function gets created.
- josevalim 3y agoI consider this to be pretty much an implementation detail though and not necessarily set in stone. The Function data structure is their public interface though and it does define an arity.
- jakear 3y agoOkay, so make the lambda's binding refer to several of those 'structs' and have .( dispatch to the correct one based on the airity at the call site.
- throwawaymaths 3y agoThat will introduce unnecessary overhead in the basic case. At some level you do want to access the "low level" function (interfacing with Erlang, e.g.) if you really want that sort of dispatch you can write your own polyfunction data type.
- deleted 3y ago[deleted]
- ajkjk 3y agoSo the answer to "why does Elixir require a dot?" is "because of dubious design choices for the innards", rather than any sort of reason that makes sense based on its actual syntax or features.
- throwawaymaths 3y agoThat's not a dubious design choice. It's actually amazing. How would you design a lambda that can be pickled and rerun across time (run on a different invocation of the vm), or space (sent across a network and executed)?
- lvass 3y ago>Why do you make me lose the ability to use Elixir's admittedly powerful Pattern matching on arity feature? If every first class fuction had to check for arity at runtime, wouldn't there be a performance cost? Also would reduce drastically the amount of errors caught at compile time. Maybe a different mechanism for dispatching like that (a macro?) could be done, how useful would that be?
- jakear 3y agoThere already must be a arity check at some point, no? If the type contained the set of airties the lambda accepts rather than just the singe one, all the same type checking could be done when it's already done.
- lvass 3y agoThere's no type checking on function dispatch unless guards are explicitly added. The arity dispatch for functions captured into first class is done at compile time and require explicitness. That said, I think you can create your own dispatch macro that's probably as efficient as possible for doing what you proposed.
- josevalim 3y ago> Why not allow function literals that define multiple arity implementations? Something like... Perhaps I was unable to get my point across but that's what the blog post is meant to answer. The TL;DR is two fold: 1. In order for the feature to be worthwhile, we should remove the distinction between name-arity pairs altogether from the language (so module functions and variables effectively exist in a single namespace) 2. However, this double namespace is a core feature of the Erlang VM, so it would require radical changes to it (or you would need a statically typed language with FFI bindings to Erlang in order to "work-around" this efficiently) Overall Elixir is a Lisp-2 language, with two distinct namespaces, and it requires conversion between functions of those namespaces. It does not have currying, it does not support point-free style, but in practice guards and pipelines help alleviate those concerns. Regarding your gist, I am honestly not sure if 15 minutes is enough to evaluate a programming language, but in case you want to dig deeper, many questions are answered in the official guides. Here are some quick links: * On maps vs keywords: https://elixir-lang.org/getting-started/keywords-and-maps.html https://elixir-lang.org/getting-started/keywords-and-maps.ht... * On do-blocks and syntax: https://elixir-lang.org/getting-started/optional-syntax.html https://elixir-lang.org/getting-started/optional-syntax.html
- jakear 3y agoRight, I wasn't putting that it forward as a sign of my deep investment in the topic. More just a laugh at dumb things I got worked up over in college. thanks for the links. That all said, I don't see why you'd need to remove the double namespace feature in order to have function literals that define multiple interpretations. The value namespace still has just the single value-land binding to the literal, only the `call` procedure (the .( operator, so to speak) needs to be modified to dispatch to the appropriate function-land name as determined by airity and the literal the value was bound to.
- josevalim 3y agoI see. :D I am lucky my time in college was just before the internet "became permanent". Double lucky that all pictures and recordings from my cover band disappeared with it! Anyway, regarding the dot, we could make `fun.(...)` dispatch to the correct arity, but that would make every function dispatch slower. However, even if we assume that's an ok price to pay, it wouldn't take long for people to request function capture without an arity, such as `&Foo.bar` (otherwise it would feel incomplete). And this feature would add further penalties as we further postpone the call. Both would also reduce the amount of compile-time checks we can emit and hurt integration with the overall Erlang ecosystem. On the large scale of trade-offs, I don't think it is worth it. :)
- munificent 3y agoWhat if you wanted your local function to shadow some of the arities of the outer function but not others?
- jakear 3y agoThere's no value/function shadowing in Elixr so it isn't possible regardless. But one could always just call the outer Function from the labmbda's innards.
- b3orn 3y agoAs far as I as an Erlang developer can say, I think there's a misunderstanding about arity in Elixir (and probably even more misunderstandings on everything else that's borrowed from Erlang). There is no "Pattern matching on arity feature". Normal functions are defined by a name and arity, `foo/1` and `foo/2` are two different functions and not two clauses of the same `foo` function. Erlang makes this clear when it forces you to export both instead of just exporting `foo`, maybe Elixir just tries to hide this limitation. Funs/lambdas are limited by this too, as another comment already showed, funs are sometimes (often?) compiled to normal functions.
- octacat 3y agoCalling function with dynamic number of arguments would be slower, if you pass that as higher-order-function. Because VM would have to figure out at runtime if it needs to execute plus/0 or plus/2 depending on number of passed arguments. I.e. slowdown without any major benefits (i.e. use case of passing function with known number of arguments is much more used comparing to "unknown number of of arguments").
- jakear 3y agoSlowdown would be imperceptible with modern branch prediction. Lay out the airity implementations in memory as a linked list, instruct users to make the first one the common case, you're golden. An index would also work, not really necessary though.
- octacat 3y agoyea, maybe. Repo is otp/erlang. PRs are welcomed ;)
- jakear 3y agoAn unsolicited PR that adds new syntax and changes the bytecode layout would 100% not be welcomed. There are stages to redesigning languages and that is the last one. But instead of having a discussion about it (stage one), people like to pretend like the current implementation is God's gift to mankind and anyone who disagrees should DIY or shut up.
- octacat 3y agowhy? would be pretty welcomed as proof-of-concept to start the discussion. Nobody has said it would be merged immidiatly. At least could be used to run load tests. You can always start with EEP if you wanna to discuss or propose new feature - https://www.erlang.org/eep https://www.erlang.org/eep