Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modules cannot have ports with same name #1450

Open
b123400 opened this issue Jul 26, 2016 · 11 comments
Open

Modules cannot have ports with same name #1450

b123400 opened this issue Jul 26, 2016 · 11 comments
Labels

Comments

@b123400
Copy link

b123400 commented Jul 26, 2016

Elm version: 0.17.0

I have two modules, they both have a port with the same name:

port module ModuleA exposing (main)

import Html exposing (text)
import Platform.Sub as Sub

port incomePort : (String -> msg) -> Sub msg

main =
  text "Hello"
port module ModuleB exposing (main)

import Html exposing (text)
import Platform.Sub as Sub

port incomePort : (String -> msg) -> Sub msg

main =
  text "Hey!"

And I compiled it by this command:

elm make ModuleA.elm ModuleB.elm --output combined.js

The generated JS file will output the following error:

Error: There can only be one port named `incomePort`, but your program has multiple.

These two modules are not connected and there should be no ambiguity between the ports. I think the ports name checking should be bounded to the module, instead of JS-file-wise.

By the way, when I generate the modules separately and include them in the same page, there is no error.

elm make ModuleA.elm --output a.js
elm make ModuleB.elm --output b.js
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>

Is this behaviour intended?

@process-bot
Copy link

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

@evancz evancz added the ports label Sep 21, 2016
@sachin-bs
Copy link

bump, any updates?

@kachkaev
Copy link

kachkaev commented Dec 6, 2017

Just raised a similar concern on stackoverflow. Being a newcomer in Elm, here is what I wanted to do to avoid import glitches:

import MyModule exposing (myFunction as myRenamedFunction, somethingElse)

Having that supported by the compiler would be awesome!

@rgrempel
Copy link

These two modules are not connected and there should be no ambiguity between the ports.

But think about the way you use the ports, on the Javascript side. You'll end up saying stuff like:

var elmApp = Elm.Main.fullscreen({
   ...
});

elmApp.ports.cacheCredentials.subscribe(function(params) {
   ...
}

Now, which cacheCredentials does this refer to, if the port name is used in two different modules?

Of course, there would be a way to solve this problem -- you could imagine elmApp.ports exposing a port name qualified by the module name, for instance -- I just wanted to point out that it's not a trivial problem to fix. Or, in other words, there is currently an ambiguity, even if you could imagine deeper changes that might avoid it.

@fdbeirao
Copy link
Contributor

I just want to post here that this talk "The Importance of Ports" by Murphy Randle has helped me (YMMV) a lot when using ports in my Elm apps. I now have one single Ports.elm module, which is the only port module and which contains two ports: infoForOutside and infoForElm. This mitigates/works around the ambiguity raised in this issue.

@noahzgordon
Copy link

noahzgordon commented Oct 31, 2018

I want to bump this, since my company ran into it in development and we were surprised by it. We compile multiple Elm apps to the same elm.js file. A coworker brought this up to me and we were able to easily resolve it by consolidating the two ports, so it's not pressing. Nonetheless, this still seems like a runtime error that could be caught at compilation instead.

@Odalrick
Copy link

Odalrick commented Nov 2, 2018

Now, which cacheCredentials does this refer to, if the port name is used in two different modules?

Obviously the one used in Main, and not the one used in OtherMain.

Tell me, if you have:

const elmApp1 = Elm.Main.init({…})
const elmApp2 = Elm.Main.init({…})

elmApp2.ports.cacheCredentials.subscribe(app2Handler)

Would you expect messages sent by elmApp1 to be recieved by app2Handler ?

I'm trying to have Elm control two different elements on the same page; let say one in the header and one in the content; and will be syncing the state between them with ports; if I could name them the same it would be clearer.

(It's probably not the best solution, but I don't know any other way and this allows me to move forward.)

@Natim
Copy link

Natim commented Sep 26, 2019

Elm 0.19

But think about the way you use the ports, on the Javascript side. You'll end up saying stuff like:

var elmApp = Elm.Main.fullscreen({
   ...
});

elmApp.ports.cacheCredentials.subscribe(function(params) {
   ...
}

Now, which cacheCredentials does this refer to, if the port name is used in two different modules?

We encountered this issue today too, @rgrempel

These two modules are not connected and there should be no ambiguity between the ports.

var header = Elm.Header.fullscreen({
   ...
});

header.ports.cacheCredentials.subscribe(function(params) {
   ...
}
var footer = Elm.Footer.fullscreen({
   ...
});

footer.ports.cacheCredentials.subscribe(function(params) {
   ...
}

I am trying to reproduce here: https://github.com/Natim/bug-1450

@Natim
Copy link

Natim commented Sep 26, 2019

I tried with Elm 0.19.1 too but I also have a runtime exception.

@malaire
Copy link

malaire commented Oct 31, 2019

This should be added to elm/core#377 (list of potential runtime exceptions).

ps. Only collaborators can comment there.

@benkoshy
Copy link

benkoshy commented Sep 24, 2020

I faced the exact same problem faced by @b123400 - if you scroll up to the first post here, you will find a beautiful minimal code example.

Here's how I solved it: I removed the port common to both the Elm modules - which were alleged duplicates, and I created a new third module which contained the port. I then imported this port into the original modules, after stripping away their old port references. This might not make much sense, so you will find below a very rough cut and paste of what I had done:

I created a new elm Module:

-- IncomePort.elm
port module IncomePort exposing (incomePort)

port incomePort : (String -> msg) -> Sub msg

And then within my other modules, I simply imported the IncomePort module and removed the old ports which existed there:

-- ModuleA.elm
-- port module ModuleA exposing (main) -- remove the port keyword at the front
module ModuleA exposing (main) -- remove the port keyword at the front

import Html exposing (text)
import Platform.Sub as Sub

-- port incomePort : (String -> msg) -> Sub msg -- remove this function which is no longer needed
import IncomePort exposing (incomePort) -- import the port from the new module

main =
  text "Hello"
-- ModuleB.elm
-- port module ModuleB exposing (main) -- remove the port at the front
module ModuleB exposing (main)

import Html exposing (text)
import Platform.Sub as Sub

-- port incomePort : (String -> msg) -> Sub msg -- remove this function which is no longer needed
import IncomePort exposing (incomePort) -- import the port from the new module


main =
  text "Hey!"

It feels hacky, but it may work for you ¯_(ツ)_/¯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests