Locally scoping imports

Sometimes I feel it’s a bit heavy handed to do the following:

import Html            exposing (..)
import Html.Attributes exposing (..)

as the names are available across the entire file.

Are local imports allowed? I.e. something like this:

view : Model -> Html.Html Msg
view model = 
    import Html            exposing (..)
    import Html.Attributes exposing (..)

    div [ class "abc" ] 
    [
        div [ id "xyz", class "bcd" ] [],

        text "123" 
    ]

I didn’t see anything in the guide about this.

Thanks!

This style is discouraged. You should import only what you need.

No.

Some of the ways I’ve seen people handle this is to use short aliases.

import Html.Attributes as Attr

and then Attr.min or you can have HA or even A instead of Attr.

You can also have a mixed approach where you expose the usual suspects and then use the namespaced version for the rare ones.

import Html.Attributes as A exposing (class, disabled, id, style)

OK, thanks for confirming, @pdamoc!

From a language design perspective, can anyone think of any downsides to the local imports feature illustrated above?

(Ignoring for now the implementation cost and whether it would be worth the feature.)

Allowing for imports to be inside functions means I can’t scan the top of a module to know what its dependencies are.

3 Likes

I usually make separate encoder and decoder modules specifically to import Json.Encode or Json.Decode. View is a module as well, both to isolate those imports a bit, and to group all the messages sent by the view.

1 Like

A related feature is SML’s local-in-end which I very vaguely miss (not just in Elm but in any language). So with local-in-end you could do something like:

local
    definition_one = ...
in
definition_two # which uses definition_one
definition_three # which also uses definition_one
end

If it were only definition_two that used defintion_one then you can quite nicely communicate that definition_one is not used outside of definition_two by simply having a let, but if definition_one is used by more than one it becomes very awkward to restrict its scope. You can do it, but it’s awkward. I feel that local-in-end really “says what I mean”. Mostly, it’s nice to restrict the scope of definition_one because then I can give it a quite short name, whereas with a larger scope I probably have to be a bit more precise in the name.

As I say, I only very vaguely miss it. But if you had that, then I would suggest that that would be one place to put in a more localised import (I haven’t used SML for a very long time, but I don’t recall being able to do localised imports using local-in-end, but it obviously could in theory be allowed).

Of course, if you generalised just a bit from there, you could just have a nested module. Since modules can already be nested there isn’t much preventing nested modules other than syntax (and the notion that a module is tied to a file).

2 Likes

That’s an interesting point!

If that is a desired requirement, I guess one way to handle it would be to still require the top-level import in order for a local import to be used. So something like this:

module Main exposing (..)

import Html
import Html.Attributes

view : Model -> Html.Html Msg
view model = 
    local import Html            exposing (..)
    local import Html.Attributes exposing (..)

    div [ class "abc" ] 
    [
        div [ id "xyz", class "bcd" ] [],

        text "123" 
    ]

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