Proposal: Add ~URI sigil

117 views
Skip to first unread message

Wojtek Mach

unread,
May 16, 2023, 4:38:01 AM5/16/23
to elixir-lang-core
Hi, I'd like to propose adding ~URI for constructing URI structs. Here's an example:

    iex> ~URI"https://elixir-lang.org"
    %URI{
      scheme: "https",
      authority: "elixir-lang.org",
      userinfo: nil,
      host: "elixir-lang.org",
      port: 443,
      path: nil,
      query: nil,
      fragment: nil
    }


I believe the advantage is we can make this a macro and thus parse the URI string at compile-time
so catch bugs because of incorrect format early (though these are pretty uncommon) and also be a
little bit more efficient at runtime.

If added, I'm not sure whether ~URI should use URI.parse or URI.new! under the hood so an advice
on that would be appreciated.

This is a separate but related discussion so while at it, I'd like to propose adding Inspect
implementation for URI that would return the sigil:

    iex> ~URI"https://elixir-lang.org"
    ~URI"https://elixir-lang.org"


I think more compact representation helps e.g. here. Before:

    iex> Req.new(url: "https://elixir-lang.org")
    %Req.Request{
      method: :get,
      url: %URI{
        scheme: "https",
        authority: "elixir-lang.org",
        userinfo: nil,
        host: "elixir-lang.org",
        port: 443,
        path: nil,
        query: nil,
        fragment: nil
      },
      headers: [],
      body: nil,
      options: %{},
      ...
    }


After:

    iex> Req.new(url: "https://elixir-lang.org")
    %Req.Request{
      method: :get,
      url: ~URI"https://elixir-lang.org",
      headers: [],
      body: nil,
      options: %{},
      ...
    }


On the other hand, seeing the internal representation right away is sometimes useful given the URI
format is somewhat subtle.

Before:

    iex> URI.parse("/foo")
    %URI{
      scheme: nil,
      userinfo: nil,
      host: nil,
      port: nil,
      path: "/foo",
      query: nil,
      fragment: nil
    }
    iex> URI.parse("//foo")
    %URI{
      scheme: nil,
      authority: "foo",
      userinfo: nil,
      host: "foo",
      port: nil,
      path: nil,
      query: nil,
      fragment: nil
    }


After:

    iex> URI.parse("/foo")
    ~URI"/foo"
    iex> URI.parse("//foo")
    ~URI"//foo"


I think this downside can be alleviated by adding `IEx.Info` implementation along these lines:

    iex> i URI.parse("/foo")
    Term
      ~URI"/foo"
    Data type
      URI
    Raw representation
      %URI{
        scheme: nil,
        userinfo: nil,
        host: nil,
        port: nil,
        path: "/foo",
        query: nil,
        fragment: nil
      }

Wojtek Mach

unread,
May 16, 2023, 4:45:42 AM5/16/23
to elixir-l...@googlegroups.com
I just realised another small benefit of showing the full URL in the sigil. Here’s a snippet from the proposal as rendered by my e-mail client:


The URL was automatically made clickable. Tools like Livebook could potentially do the same.

--
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-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/9cc29c5e-ca64-42b3-83f8-84c60985efedn%40googlegroups.com.

Kip Cole

unread,
May 16, 2023, 7:51:21 PM5/16/23
to elixir-l...@googlegroups.com
I think this is a good proposal, as is the ~UTC one.  Both make the intent much clearer.

On 16 May 2023, at 6:45 pm, Wojtek Mach <woj...@wojtekmach.pl> wrote:

I just realised another small benefit of showing the full URL in the sigil. Here’s a snippet from the proposal as rendered by my e-mail client:

<PastedGraphic-1.png>

Christopher Keele

unread,
May 18, 2023, 1:37:37 AM5/18/23
to elixir-lang-core
I dislike +1 posts, but I feel very strongly about this—it'd be amazing to have.

I want booting an application to fail as fast and obviously as possible if someone gives it a bad phoenix host url, ecto database url, rabbitMQ url, redis url, mongodb url, etc. Preferably, before the connection is attempted; which, depending on the library in question consuming the url, often fails with a confusing network-failure-related error message.

Ben Wilson

unread,
May 18, 2023, 10:25:35 AM5/18/23
to elixir-lang-core
Question: Would this sigil support interpolation? Is that too clever?

~URI"https://#{path}?#{query_params}"

- Ben

José Valim

unread,
May 18, 2023, 10:33:10 AM5/18/23
to elixir-l...@googlegroups.com
Uppercase sigils do not supported interpolation, so that's a no-go.

Note you can also get the compile time behaviour today by doing @uri URI.new!("...").

Reply all
Reply to author
Forward
0 new messages