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

Better handle inner modules #54

Closed
bryanjos opened this issue May 29, 2015 · 8 comments
Closed

Better handle inner modules #54

bryanjos opened this issue May 29, 2015 · 8 comments

Comments

@bryanjos
Copy link
Collaborator

Testing out inner modules and realized there are some issues. The biggest being they export the default object as well creating more than one export default in a file. Same thing goes for the __MODULE__ definition. Need a new way of handling the __MODULE__ translation, and probably need to put inner modules as a property on the outer object. There should only be one export default per file.

@bryanjos
Copy link
Collaborator Author

This probably will have an effect on how modules are translated

@bryanjos
Copy link
Collaborator Author

Still thinking this through. I haven't come up with a plan yet, but I have thought about some options.

One would be to check for inner modules, translate them into a function and export them with the outer module's export statement. The problem here is when aliasing, etc, it would currently break with the way they are translated into imports.

Another would be to take the module and make it into it's own file. This would remove the issues laid out above. I would require some updates to the translation of modules, but nothing too bad.

I'm not sold on either of those and would love any thoughts, feedback, or ideas.

@bryanjos
Copy link
Collaborator Author

Ok, so I think I've come up with a plan for modules.

Elixir modules don't really match up with ES6 modules as well as one would like. For instance, you could create a module inside of a function if you wanted to. So my proposal for updating modules is to do the following:

  • Modules would no longer be ES6 Modules and module creation will be a function closure the returns an object with public functions. All of the object would be in the global scope.
defmodule Hello do

  @some_attr "hello"

  defp private_function() do
  end

  def public_function() do
  end

end

Would turn into this

const Hello = (function(){
  const __MODULE__ = Atom("Hello")
  const some_attr = "hello"

  function private_function(){
    return null;
  }

  function public_function(){
    return null;
  }

  return { public_function: public_function }
})();

inner modules would work similar:

defmodule Hello do
  @some_attr "hello"

  defmodule World do
  end

  defp private_function() do
  end

  def public_function() do
  end

end

Would turn into this

const Hello = (function(){
  const __MODULE__ = Atom("Hello")
  const some_attr = "hello"

  let World = (function(){
    const __MODULE__ = Atom("World")
  })();

  function private_function(){
    return null;
  }

  function public_function(){
    return null;
  }

  return { public_function: public_function, World: World }
})();

An added benefit to this would be that one would no longer have to explicitly use aliases for modules. Aliases would just end up as const declarations to pointing to the specific module.

For using other JS libraries, one could use them globally or a macro would be added specifically for importing js libraries. An added benefit of using the macro is that it helps keep Elixirscript as standard Elixir. The :from clause currently added to the alias, import, and require isn't standard Elixir so removing that would good.

This may also help down the line with protocols as well. An added benefit is th

@bryanjos
Copy link
Collaborator Author

Option 2 would be making them into classes. I just don't like ES6 classes that much (personal preference).

@togakangaroo
Copy link

What about dependencies and module loading? What happens with that stuff?

@bryanjos
Copy link
Collaborator Author

They will either be reference by their full names are can be aliased. For example:

defmodule Hello do
  alias Another.Module.World
  js_import JQuery

  def something() do
    Some.Other.Module.do_it()
    World.do_it()
  end
end

would be translated to

const Hello = (function(){
  const __MODULE__ = Atom("Hello")
  const World = Another.Module.World
  import JQuery from 'jquery'

  function something(){
    Some.Other.Module.do_it();
    World.do_it();
  }

  return { something: something }
})();

In this example, since the modules will be in the same scope, they can be accessed without having to import them in. This works more in line with Elixir. Also, you saw an example of what an alias would do.

Lastly I added an example of how an ES6 module could be added. A macro (in the example js_import) could be used to import JavaScript ES6 modules. Libraries in the global scope would not have to be imported explicitly either.

The only issue for importing ES6 modules would be that import statements are hoisted to the top. That would mean that a module that imported an ES6 module could have that ES6 module used by another module here. That doesn't cause to much of a concern though..

@bryanjos
Copy link
Collaborator Author

@togakangaroo here is the link the the defmodule documentation for Elixir. Maybe it would give you some ideas as to how I could do this a better way. I like your idea of using something such as System.define, but not sure if it would work out well.
http://elixir-lang.org/docs/stable/elixir/Kernel.html#defmodule/2

@bryanjos
Copy link
Collaborator Author

So I ended up reverting back to making the modules into ES6 modules. I'm pulling out the inner modules and they are being placed into their own files. I'm also automatically creating an import statement for them in the modules containing them. The solution should resolve this issue.

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

No branches or pull requests

2 participants