New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
object-like notation for module functions #6012
Comments
Comment author: @dbuenzli I would be against such an addition. I think there are already enough notations in OCaml, the language is already sufficiently complex. Moreover it would encourage an imperative style of programming. I think you should consider using the M.() notation for that need. ClassModule.(self meth1 args; self meth2 args; self meth3 args) Now maybe the M.() notation should just fix the precedent it introduced that its parens cannot be replaced by begin end (which if I'm not mistaken was true in the expression language before). So that you could write ClassModule.begin Though it should be noted that M.() should not be abused, as it has its own problems see #5980. |
Comment author: @lefessan I don't see what you mean by "encouraging imperative style", the notation is for calling functions, as shown by my (functional) example on lists, so it does encourage either style of programming. I think there are two caveats with using M.() notation: (1) it opens the whole M module, so that there can be collisions with identifiers used in the arguments. With my notation, only the method is prefixed with the module name, so there can be no mistake. (2) it is not attached to a given identifier. If I have obj1->meth1 args1; where obj1 and obj2 use two different modules, my notation is still shorter and unambiguous, while other notations have either to explicit the modules everywhere, or hope there is no collisions between them. |
Comment author: @gasche I would tend to agree with Daniel that this is maybe not a good use of the (little) free syntactic space with have left. The fact that it overlaps in purpose with the object or record projection on one side, and the local opening on the other is suspicious. On top of Daniel's suggestion to use local module opening for that, you could make use of a reverse application operator as well: let open Module in Daniel : parenthesis (vs. begin/end) have had a special status in the annotation/coercion syntaxes as well: (foo : t), (foo :> t) and (foo : t :> t). I'm not for or against "Foo.begin ... end" (it's fine if it doesn't add ambiguities in the grammar), but I would prefer the more explicit "let open Foo in" for non-one-liners anyway. |
Comment author: @dbuenzli My point about encouraging imperative style was that this idea seems to stem from imperative code you are disatisfied with. If your idea is to add new notation for calling function I really think it's not only pointless, but also harmful. It' just going to increase the cognitive burden on code readers and lead to generalized confusion (funny you mention beginners in your first message). This will just be another opportunity to dilute OCaml's programming style and make it a harder language to understand in general. The difference between --> and -> maybe easy to miss and the whole idea seems rather ad-hoc from a syntactic perspective. What do you for fold_left ? l--->fold_left f acc and for fold_right are you going to permit that : l-->fold_right f acc Now think about the difference between (if you don't have both things side-by-side) l0--->fold_left2 f acc l1 and l0---->fold_left2 f acc l1 If you want to increase the power of the language for obfuscated OCaml contests, that could be a good addition. |
Comment author: @dbuenzli Side note: your original problem may not be unrelated to the fact that usually when you do bindings to a library written in another language you end up programming with the idioms and style of that other language. Making thin bindings is (mostly) the easy part. Building on top of these an (as light as possible) abstraction that exposes that functionality naturally in your language is where the challenge resides. |
Comment author: @bobzhang I am for such proposal, 'let open M in' is too dangerous for real world usage, we can reuse '|>' syntax for functional style. let (m:M) = Here no 'let open' |
Comment author: @lefessan I don't think having an additional notation would be a problem for beginners, when it is easy to understand. It is easy to explain how this new "->" notation works, which is not the case when using objects and their error messages... The "--->" notation was just to generalize "->" to arbitrary position. Personally, I only care about "->" that adds the "object" as the first argument. Still, I don't think "-->" is so ugly, and the existence of a shorter notation does not force programmers to use it for cases like fold_left2 ! |
Comment author: @garrigue First question: is your problems with objects only errors, or are they really a bad fit. As for the need to use scope information obtained during typing, I think this is mostly about making it more robust (have an error if the definition of l has been shadowed). Otherwise this can be completely syntactic, and you can already do that with Camlp4. The error message in case of shadowing will just be less explicit. But in fact making it completely syntactic is nicer in some situations: let f ( l -> List) = Just by keeping the same name you can go on using the syntax in functional code. |
Comment author: @lefessan @garrigue: My other problem with objects is that I think late binding of virtual methods makes code unreadable, you have to always search among all the classes in a hierarchy to understand which code is really executed. It is nice for prototyping fast, but makes the code harder to maintain on the long term. So, when I can, I just avoid it. 2/ Indeed, it can be done with camlp4, and you have a point that it makes sense to have a purely syntactic behavior. Anyway, my initial question was "does anybody else feel the need for it ?", because if many would have replied yes, it would have been interesting to have it in the standard syntax instead of just an extension. |
Comment author: @garrigue
I think there is an agreement that blanket -warn-error A in published code is a very bad idea. |
Comment author: @alainfrisch My personal opinion is that the proposed feature does not bring enough to the language to justify the introduction of a new concept and syntax. |
Comment author: @gasche Being in a bug-triaging mood I'm tempted to mark this bug as something else than "new". As it looks there is more opposition to the feature than support, I'm preparing for it to be thrown in the dustbin of history by marking it "suspended", but that's more because all the other "status" choice were less convincing than because I think there is no more discussion to be had on the issue -- I'm hoping it will die down by itself, but strong arguments in either direction are welcome. (On a strictly personal level I don't really like the feature, but have no strong argument either against -- it's just that I think we can find better use for whatever notations could be chosen. I think the "purely syntactic" version would be better: what we are discussing is a "notation" in the spirit of Coq's Notation mechanism or Agda's more recent "syntax" binding feature. A classification which is maybe not a compliment.) |
Original bug ID: 6012
Reporter: @lefessan
Assigned to: @gasche
Status: resolved (set by @gasche on 2013-05-17T16:36:29Z)
Resolution: suspended
Priority: normal
Severity: feature
Category: ~DO NOT USE (was: OCaml general)
Bug description
I have been recently translating a lot of code from C++ to OCaml, but without using OCaml objects (for my purpose, they trigger errors that are hardly understandable by beginners...). I usually end up translating a lot of calls of the form:
self.meth(args)
to
ClassModule.meth self args
While it is easy to do it using replace-regexp, I was wondering if it would not be worth adding a simple syntax for that, that could also be used in a more general context to reduce the size of code to look like object-oriented code without using objects. The idea is that a common idiom in OCaml is to put all the functions working on a specific type in a module, and thus, if we can associate syntactically an identifier with such a module, we can use some object-oriented notation to access all these functions for this identifier (here, I will use "->" for that).
In the above example, when "self" would be introduced in the context, it would be associated with ClassModule (like a type annotation):
let f (self -> ClassModule) =
...
self->meth1 args;
self->meth2 args;
self->meth3 args;
...
With arrays:
let list_plus_length ( l -> List ) =
let len = l->length in
l-->map (fun i -> i + len) (* --> put "l" as the second argument of List.map *)
Note that it is not purely syntactic, it must be done with the knowledge of scopes, i.e. during typing. An extension would be to associate modules with types, so that type knowledge would trigger the correct use of functions :
type string -> String
let len (s : string) = s->length
Another advantage of such a notation would be that editors could use their knowledge of the module associated with the identifier to propose completions within that module.
Anybody else interested in having such a notation ?
The text was updated successfully, but these errors were encountered: