Multiple aliases in one line with as:

Is there a way to have multiple aliases, but to use as: acronym for one of them, something like this, but that actually works :smiley:

alias Guard.Rbac.{Cache, RoleBindingIdentification, as: RBI}

1 Like

What you show in best case could work as:

alias Guard.Rbac, as: RBI
alias Guard.Rbac.{Cache, RoleBindingIdentification}

That’s because opts are on same level as other aliases.

Alternatively Elixir could support this:

alias Guard.Rbac.{Cache, {RoleBindingIdentification, as: RBI}}

However this looks just ugly and I guess that’s why it would be not supported at all. If you have an interesting idea how to improve that then feel free to create a proposal, but so far I do not see either a use case nor how it could look good at all.

Also keep in mind that even if such ugly-looking feature would be supported then it would be still formatted into multiple lines, so it would look like:

alias ParentName.{
        {ChildA, as: A},
        ChildB,
        {ChildC, as: C}
      }

I believe that keeping aliases work as it’s now is best.

2 Likes

This is exactly what I meant :smiley: I dont agree that this is ‘ugly looking’. Elixir already supports this notation:

alias ParentName.{
    ChildA,
    ChildB,
    ChildC
}

and I don’t see how this is any prettier (or less ‘ugly-looking’) then the example above where abbreviations are supported.

True, situations where something like this would be needed are rare, but option 1:

alias Guard.Repo.{
    RbacUser,
    UserGroupBinding,
    RbacRole,
    {OrgRoleToProjRoleMapping, as: Mapping}
    RoleInheritance,
    SubjectRoleBinding,
    {RoleBindingIdentification, as: RBI}
    Permission,
    Scope
  }

IMO looks cleaner then option 2:

alias Guard.Repo.OrgRoleToProjRoleMapping, as: Mapping
alias Guard.Repo.RoleBindingIdentification, as: RBI
alias Guard.Repo.{
    RbacUser,
    UserGroupBinding,
    RbacRole,
    RoleInheritance,
    SubjectRoleBinding,
    Permission,
    Scope
  }
1 Like

I don’t understand what that’s trying to specify. In this case, one is able to guess, though.

For me personally, I enforce the Credo.Check.Readability.AliasAs and Credo.Check.Readability.MultiAlias Credo checks for alias, among others. So the alias ___.{___} syntax and alias ___, as: ___ are not allowed.

Mutli aliasing is really only useful in very specific scenarios. It makes copying module names harder (impossible rather), and it starts to look ugly and busy when you have a lot of modules that aren’t just under a single “namespace”. Simply typing out the shared “namespace” is really not difficult.

I personally feel that alias ___, as: ___ should be used extremely sparingly if not removed from the language. It’s use is usually an indication that the module it is asing is poorly named. And I have certainly seen it heavily abused where the module was essentially renamed with as.

For the proposed:

alias Guard.Repo.{
    RbacUser,
    UserGroupBinding,
    RbacRole,
    {OrgRoleToProjRoleMapping, as: Mapping}
    RoleInheritance,
    SubjectRoleBinding,
    {RoleBindingIdentification, as: RBI}
    Permission,
    Scope
  }

it requires a fair amount of tracing to understand. I would suggest renaming the longer modules. RoleBindingIdentification could be RoleBindingId or even just RBI if you documented it with @moduledoc and the abbreviation is clear in the context. OrgRoleToProjRoleMapping should probably just be renamed.

3 Likes

Using rarely, yes. Removing? No!

We have a codebase with more than 600 modules at work.

There are several modules ending in Product, within Schema, Dataloader, and what not prefixes. We do not want to repeat the type in the module name itself, therefore we are happy to be able to use :as in an alias.

5 Likes

Removed was a bit of a hyperbole. :stuck_out_tongue_closed_eyes: I know it won’t and probably shouldn’t happen in Elixir. Although, certainly several other languages, such as F#, do not have that feature, and I personally don’t miss it there. I’m not aware of it being in Erlang. Is that correct?

For Elixir, I got a bad taste for it at my previous company, where its use was definitely a symptom of poorly named modules. So many modules had such extremely similar names that as: ___ was used to mitigate this in modules and in tests. The moral of the story is that people will often take conveniences and turn them into hazards. :upside_down_face:

1 Like

And how do you deal with external librarie modules?

Erlang doesn’t have module aliasing at all.

I’d say the biggest reason why as: is bad because if you wanted to do a global search and replace during refactoring, it makes it much more difficult.

Same with alias Module.{
}

I use neither in my codebases.

2 Likes

Ya, I’m not a huge fan of {} (though it has its uses though wouldn’t miss them if they were gone) and never use :as. I even avoid just plain old alias a lot of the time unless it provides significant noise-reduction.

One of the big things that drew me to Elixir was the high level of locality that is encouraged through official examples. I’m even just talking things like, Enum.map as opposed to import Enum, only: [:map, 2]. Jumping into a function to gain a bit of context on its caller and being able to see all its dependencies without having to jump any further is a really nice feeling. Of course, it’s a balance, but I feel that often there is a subconscious emphasis put on writeability or even “prettiness” over readability and, more importantly, “scannability”.

And of course the other thing I really like about Elixir is how relatively small it is and how much thought is put into backwards incompatible changes. Just by that alone, I don’t see something like nested :ases ever making it in (not that you were necessarily suggesting they would be). Take this really well-thought-out proposal for field punning—a featured loved by many in other languages (not me)—that was rejected, for example.

1 Like

Yes, there is!

Behold the dark art of context magic in Elixir

 alias (alias Guard.Rbac, as: RBI).{Cache, RoleBindingIdentification}

Please do not try this at home

2 Likes

If I understand correctly, in your example RBI.Cache would ‘expand’ to Guard.Rbac.Cache, and same go for RBI.RoleBindingIdentification which would expand to Guard.Rbac.RoleBindingIdentification, right?

How about:

alias Guard.Rbac

alias Rbac.{Cache, Other, Baz}
alias Rbac.SomethingReallyLong, as: Long

alias Long.{Child, Child2}

It’s a little more but is easy to read.

1 Like

Yes, that’s correct