Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

gasche
Copy link
Member

@gasche gasche commented Jun 30, 2023

Forbid type t = Foo of M.(bar * baz) which could be understood as two separate constructor arguments M.bar and M.baz or a single tuple type.

See #12044 (comment) -- thanks are due to @hypenrf for the report and @let-def for the implementation.

end
module StaticVersion = struct
let require_20210419 = ()
let require_20220210 = ()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are increasing the menhir version, shouldn't we move to the last released version?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my book, any move to a more recent version is fine.

| atomic_type_without_open
%prec below_HASH
{ Pcstr_tuple [$1] }
| ty = atomic_type STAR tys = inline_separated_nonempty_llist(STAR, atomic_type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: we could also disallow Foo of M.( x ) * N.( y ) to make it less surprising than Foo of M.(x) is a syntax error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, or maybe it would be possible to allow Foo of M.(x). I will try that and come back to confirm that it is hell.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that having Foo of M.(x -> y) allowed but not Foo of M.( x * y) would not be an improvement in term of the readability of the grammar.

@gasche
Copy link
Member Author

gasche commented Jun 30, 2023

On a suggestion by @Octachron, local open is now systematically disallowed in constructor arguments for consistency: the change proposed by @let-def would allow Foo of M.(r) * M.(t) but reject Foo of M.(r), and now both are rejected.

@yallop
Copy link
Member

yallop commented Jun 30, 2023

Personally, I'm happy with allowing type t = Foo of M.(bar * baz) and interpreting it as a single tuple argument, since I think of M.(...) as enhanced parentheses.

@gasche
Copy link
Member Author

gasche commented Jun 30, 2023

I don't necessarily disagree. On the other hand, I see the following arguments in favor of restricting:

  • If unsure, restrict more, it is easy to allow later.
  • If people make the wrong guess that of M.(r * s * t) has several arguments -- what would be written M.(r and s and t) in revised syntax -- then it is very hard for them to realize their mistake, and they silently get a worse value representation. In the direction, if you are surprised by a syntax error but really want to use the local-open syntax as a single argument, then writing (M.(r * s * t)) is ugly but low-pain.

@hyphenrf
Copy link
Contributor

hyphenrf commented Jul 4, 2023

Personally, I'm happy with allowing type t = Foo of M.(bar * baz) and interpreting it as a single tuple argument, since I think of M.(...) as enhanced parentheses.

if that's the case, how would you express multiple constructor args with a local open?

@gasche
Copy link
Member Author

gasche commented Jul 4, 2023

@hyphenrf note that there isn't currently a syntax to allow a local open around several arguments. (And I'm quite sure that it would be a bad idea to use of M.(... * ... * ...) for this.).

One can of course use

open struct
  open M
  type t = ...
end

at the level of one or several structure items.

@yallop
Copy link
Member

yallop commented Jul 4, 2023

if that's the case, how would you express multiple constructor args with a local open?

I don't think it matters if it's not possible to express that with a single local open; there are lots of things local opens can't do. I think it's more important to have a uniform rule, like "M.(te) can go anywhere a type expression can go".

@lpw25
Copy link
Contributor

lpw25 commented Jul 5, 2023

like "M.(te) can go anywhere a type expression can go"

I would argue that rule is respected either way here, as the debate is really about whether the argument to a constructor is a single type expression or a sequence of type expressions separated by *. I think it is the latter hence why I think it should be an error, but the other position is also consistent.

@yallop
Copy link
Member

yallop commented Jul 5, 2023

Disallowing T of M.(x) * M.(y), as the PR currently does, seems unambiguously inconsistent with the rule.

@gasche
Copy link
Member Author

gasche commented Jul 5, 2023

To recap, there are three choices:

  1. trunk: allow of M.(foo) and of M.(a) * M.(b)
    justification: M.(ty) is a single type expression (despite the potential for confusion for M.(a * b))
  2. the first iteration of this PR: disallow of M.(foo) but allow of M.(a) * M.(b)
    justification: of M.(a * b) could be perceived as ambiguous, so we reject it as a special case
  3. the second/current iteration of this PR: disallow both of M.(foo) and of M.(a) * M.(b)
    justification: to avoid any perceived ambiguity, constructor arguments cannot start with a toplevel local-open

I find (1) and (3) both conceptually simpler than (2), and the grammar is also simpler.

In all cases of (M.(foo)) is allowed, because this is clearly unambiguous (it is an explicitly-disambiguated form). There is no corresponding explicit-disambiguation for the other interpretation. (I think M.(Foo of ...) would be the most natural syntactic choice.)

@gasche
Copy link
Member Author

gasche commented Aug 3, 2024

I think that it may now too late to improve on this, local open in types has shipped without it and we haven't managed to build a consensus to restrict it here. Closing.

@gasche gasche closed this Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants