> On 31 May 2024, at 12:32, José Valim <jose.va...@dashbit.co> wrote: > > I have reviewed the pull request and I noticed that it does validate the URL > before generating URI.new!, but it now has the unfortunate side-effect that > you may have 2 (or 3) distinct representations when inspecting, which is > another downside of the proposal. I don't think the cons (multiple > representations, hiding of structures) justify the pro of a more succinct > representation.
I agree, 3 representations is probably too much, I think having just 2, URI.new! and %URI{}, is more palatable. This reminds me that we used to print `%{~D[2024-01-01] | calendar: Calendar.Holocene}` as `%Date{year: 2024, month: 1, day: 1, calendar: Calendar.Holocene}` so FWIW there was some precedent for this. (It has been improved since, though, and nowadays it would have printed: `~D[2024-01-01 Calendar.Holocene]`.) If discoverability is more important than verbosity then that’s that. I personally don’t think it matters that much, we have good error messages when mistyping field names and we have the |> inspect(structs: false) and IEx.Info “fallbacks”. Here’s somewhat contrived example so take it for what it is but the difference is pretty stark: ``` iex> Enum.map(1..5, &URI.new!("https://example.com/foo?x=#{&1}")) [URI.new!("https://example.com/foo?x=1"), URI.new!("https://example.com/foo?x=2"), URI.new!("https://example.com/foo?x=3"), URI.new!("https://example.com/foo?x=4"), URI.new!("https://example.com/foo?x=5")] ``` ``` iex> Enum.map(1..5, &URI.new!("https://example.com/foo?x=#{&1}")) [ %URI{ scheme: "https", userinfo: nil, host: "example.com", port: 443, path: "/foo", query: "x=1", fragment: nil }, %URI{ scheme: "https", userinfo: nil, host: "example.com", port: 443, path: "/foo", query: "x=2", fragment: nil }, %URI{ scheme: "https", userinfo: nil, host: "example.com", port: 443, path: "/foo", query: "x=3", fragment: nil }, %URI{ scheme: "https", userinfo: nil, host: "example.com", port: 443, path: "/foo", query: "x=4", fragment: nil }, %URI{ scheme: "https", userinfo: nil, host: "example.com", port: 443, path: "/foo", query: "x=5", fragment: nil } ] ``` Can’t say I run into stuff like this very often but on the rare occasion I wouldn’t mind something way more compact so I could focus on what matters (i.e. not the internal structure) Anyway, thanks for considering this! > > On Fri, May 31, 2024 at 12:20 PM José Valim <jose.va...@dashbit.co > <mailto:jose.va...@dashbit.co>> wrote: >> There are some issues with this proposal: >> >> 1. URI parse does not validate, it only parses the components, which means >> inspecting with URI.new! after URI.parse! does not guarantee it will be >> parseable and return the same result back. >> >> 2. URI.new! (and similar) hide the underlying fields of the URI, making them >> harder to discover. I believe URI.new! (and similar) are almost always >> justified when the structs fields are private, which is not the case here, >> so there is more space for debate >> >> If the main goal is to reduce verbosity, then maybe we should consider >> tagging all fields as optional, so we have this instead: >> >> iex> URI.new!("https://elixir-lang.org <https://elixir-lang.org/>") >> %URI{ >> scheme: "https", >> host: "elixir-lang.org <http://elixir-lang.org/>", >> port: 443 >> } >> >> It may be an acceptable trade-off between hiding fields and keeping it more >> compact. >> >> On Fri, May 31, 2024 at 12:13 PM Wojtek Mach <woj...@wojtekmach.pl >> <mailto:woj...@wojtekmach.pl>> wrote: >>> The current inspect implementation is pretty verbose: >>> >>> ```elixir >>> iex> URI.new!("https://elixir-lang.org <https://elixir-lang.org/>") >>> %URI{ >>> scheme: "https", >>> userinfo: nil, >>> host: "elixir-lang.org <http://elixir-lang.org/>", >>> port: 443, >>> path: nil, >>> query: nil, >>> fragment: nil >>> } >>> ``` >>> >>> I'd like to propose a more concise one along the lines of "Expression-based >>> inspection" from ELixir v1.14 >>> <https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#expression-based-inspection-and-inspect-improvements>: >>> >>> ```elixir >>> iex> URI.new!("https://elixir-lang.org <https://elixir-lang.org/>") >>> URI.new!("https://elixir-lang.org <https://elixir-lang.org/>") >>> ``` >>> >>> There is a subtle difference between `URI.new!/1` and `URI.parse/1`, the >>> former sets the deprecated `authority` field to `nil` so this proposal >>> takes that into consideration, returns `URI.parse` "as is": >>> >>> ```elixir >>> iex> URI.parse("https://elixir-lang.org <https://elixir-lang.org/>") >>> URI.parse("https://elixir-lang.org <https://elixir-lang.org/>") >>> ``` >>> >>> `URI.new!/1` is stricter than `URI.parse/1` and in particular it does not >>> allow non-escaped characters, notably `"` and `(` and `)` which would >>> conflict with the inspect representation so for these I propose to return >>> `%URL{}`: >>> >>> ```elixir >>> iex> URI.parse("https://elixir-lang.org/\ <https://elixir-lang.org/%5C>"") >>> %URI{ >>> scheme: "https", >>> authority: "elixir-lang.org <http://elixir-lang.org/>", >>> userinfo: nil, >>> host: "elixir-lang.org <http://elixir-lang.org/>", >>> port: 443, >>> path: "/\"", >>> query: nil, >>> fragment: nil >>> } >>> ``` >>> >>> I vaguely remember previous discussions about this and I believe the >>> biggest concern was "hiding" the internal structure. For example, what is >>> the `:scheme`, `:host` and `:path` in intentionally mistyped URL >>> `http:/foo`? We would not get the answer from Inspect: >>> >>> ```elixir >>> iex> URI.new!("http:/foo") >>> URI.new!("http:/foo") >>> ``` >>> >>> but I'd like to propose to additionally implement `IEx.Info`: >>> >>> ``` >>> iex> i URI.new!("http:/foo") >>> Term >>> URI.new!("http:/foo") >>> Data type >>> URI >>> Description >>> This is a struct representing a URI. >>> Raw representation >>> %URI{scheme: "http", authority: nil, userinfo: nil, host: nil, port: 80, >>> path: "/foo", query: nil, fragment: nil} >>> Reference modules >>> URI >>> Implemented protocols >>> IEx.Info, Inspect, String.Chars >>> ``` >>> >>> PR: https://github.com/elixir-lang/elixir/pull/13623 >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "elixir-lang-core" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to elixir-lang-core+unsubscr...@googlegroups.com >>> <mailto:elixir-lang-core+unsubscr...@googlegroups.com>. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/e36197aa-1b77-4000-a3b2-55f022e20ce1n%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/elixir-lang-core/e36197aa-1b77-4000-a3b2-55f022e20ce1n%40googlegroups.com?utm_medium=email&utm_source=footer>. > > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-core+unsubscr...@googlegroups.com > <mailto:elixir-lang-core+unsubscr...@googlegroups.com>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J2z%2B4LmR49nehE_GD8qeZye%3D867PfGuvTcf%2BSzWcyPtg%40mail.gmail.com > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J2z%2B4LmR49nehE_GD8qeZye%3D867PfGuvTcf%2BSzWcyPtg%40mail.gmail.com?utm_medium=email&utm_source=footer>. -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/FC8602E3-CE2E-4F6D-9873-A16CB736080B%40wojtekmach.pl.