Dot notation for "Methods"

By inspiration from the Lean4 language I suggest a dot notation for “methods”.

I don’t see this as adding much value, and it complicates the language.

The convention in Elm is to make the “main object” the last parameter and use |>. Is there really a need to add a.doStuff arg when we already have a |> doStuff arg?

2 Likes

I guess. I like the pipe syntax. Lean4 has both the |> and . notation, but it’s use cases are different. The main point is perhaps the point of “namespacing” inside modules. Since you could have several A.doStuff and B.doStuff, and the compiler could figure out which to use based on the type name. One can ofc just write the module name right now, but in my code I have many long type names that would be nice to not always have to write.

import MyVeryVeryLongNamedModuleForCats as Cats
1 Like

@rupert Yes, I know. I might be just lazy, but I would want that convenience sometimes.

Allowing more than one symbol with the same name but different types does seem like a feature that could be nice, although I can also see some people thinking it could make code harder to reason about. That change does not need to be coupled with the new syntax, though.

I like the dot notation for the “auto-completion” features it provides in other languages editor tools.

The pizza requires two special character keypresses, both requiring the shift key, and never “auto” completes based on the context from the left side of the pizza.

import List
[ 1, 2, 3 ] |> List.first
--vs
Import List
[ 1, 2, 3 ].first 

(Implicitly uses the “first” from the list module, if its the only matching imported function. Could match on imported method that takes a list as the final argument.) Could maybe work something like F# extension methods.

Would be nice, but as others say I guess there are good reasons for not including it. I’m not a language designer. I like the question and suggestion though!

Philosophy : You Write Code For Others

The total time of code management includes

  • writing & modifying
  • reading & understanding

In my experience the second component is where you lose time and money unless in pet projects.

Now let’s say we meet an expression x.first somewhere in the code, it can mean either x : List a or x : {first : b}, and we need to go read where x was initialized.

This breaks the flow of reading the code, and in the end would be very detrimental to code maintenability - which is by far my favorite Elm feature.

12 Likes

I do like that most IDEs know how to auto complete methods. I hope the elm language server will know at somepoint how to autocomplete after seing a |> by looking for functions in scope with the same type for their last argument.

10 Likes

The autocompletion functionality is a property of the editor/LSP, not the language here. There’s no reason |> couldn’t have type assisted autocompletion, it just hasn’t been implemented.

4 Likes

Show us some code that you have, or have found, that you think would be improved by a “dot notation for methods”. Show us the updated code which uses the new feature and explain what advantages you think it has, and any disadvantages. Your argument is then that this kind of code occurs often enough that the benefits (advantages - disadvantages) outweigh the cost of increasing the complexity of the language.

If your example code already exists so much the better. It could exist in standard or heavily used libraries, or well presented examples. This demonstrates well that the code situation you are describing occurs naturally, and you’re not making up a contrived example.

I find that whenever I consider a new language feature, a first step is looking for code that would be improved by such a feature, and I often find I’m struggling. In that case, it’s going to be a very hard struggle to convince anyone. You would have to demonstrate that such code doesn’t exist because the feature doesn’t exist and so developers are working around that at a higher level.

One of the things I like about Elm is that it does NOT have dot methods, because the way they are used in many languages creates a lot of ambiguity: if I see foo.bar in Python, I do not know from context if bar is a field on this specific instance of foo, or a method associated with whatever type Foo is.

So if nothing else, I would ask that if there ever is a way to name a method by association with a variable, it uses something other than . to do it so that no new ambiguity is introduced.

(Even in Elm, there are a lot of cases – because of modules, and because Foo.Bar in a type signature is a type, but Foo.Bar in any other context is a reference to a constructor named Bar in the module named (or aliased) to Foo… no need to add more!)

1 Like

I also left some comment in the original issue. Anyway maybe it’s worth also asking here. Perhaps I’m missing something but I wonder…

With this proposal I wonder what you would expect for this code to produce:

adding_one t =
  t.map (\a -> a + 1)

My take

I can imagine primarily 2 expected results…

Ad-hoc Polymorphism

This code should compile and work so that I can call:

adding_one (Just 1)
--> Just 2

adding_one [1, 2, 3]
--> [2, 3, 4]

Anyway as you can see this introduces new type of polymorphism which is currently not possible in elm. The type would be something like:

adding_one : f Int -> f Int

where f is of kind kind f = Type -> Type (imaginary kind annotation since at the moment elm doesn’t have any).

This Code should be rejected

Compiler should error with something can't specialize f in ... prohibiting you from using this feature in this way. In such case you would need to somehow specify which type does t have like:

adding_one : Maybe Int -> Maybe Int

Anyway as you can see this syntax would break type inference in a way it would no longer be possible to infer type without this annotation.

Also in my opinion this makes whole feature kind of useless. It would make . just an alternative syntax for |> which (unlike existing |>) is also ambiguous. This code which is already possible at the moment doesn’t have this problem and provides exactly the same capabilities:

adding_one f =
  f |> Maybe.map ((+) 1)
1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.