-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Add # elixir-mode:
to .exs
files to enable Mix.install/imports in same file
#14037
Comments
Forgive me, but we can define the mode wherever we want (comment, CLI argument or so), right? In that case instead of $ elixir example.exs --mode expr-eval Since we are doing this for #!/usr/bin/env elixir --mode expr-eval
# ^^^ Let shell handle above ^^^
defmodule Person do
defstruct [:first_name, :last_name]
end
person = %Person{first_name: "John", last_name: "Doe"}
IO.inspect(person, label: "person") so we can add executable permission using If what I wrote is possible then adding "special comment" does not makes much sense as we (or rather the shell) already supports one special comment which we can use. What do you think about it? |
I don't have a strong opinion, for my usecase that would work just fine. However for completeness, I can see one downside. Making it only a CLI flag in the shebang is that one might write a script that expects In my mind the evaluation mode is a concern of the script being run, not that of who is running it. Now I don't know the internals of Elixir well enough to say for certain, but there also may be some weird interplay with Feels to me the special comment is the more robust solution and more forward looking, but as I said, I personally
Either way, works for me though |
I see the point, but running a executable script with
Support
However I would still prefer 1st option, because:
As above a comment way looks more "hidden" - something that people may remove not understanding what it do, because "it's just a comment". It would make people search for the problem without giving any hint. |
I’m very much looking forward to this! I keep thinking about one thing though, I wonder if instead of having a magical comment (and setting a precedent for it), could we have something like: Code.mode(:eval_expr) which would look like regular code but it would be totally hardcoded by tokenizer/parser (just like a magic comment would) i.e. can only be the very first line (optionally after unix shebang). If that would be possible, I think the biggest benefit would be that we could document it. |
I'm not particularly convinced by those solutions. In the case of error messages you'd have to keep a list of growing usecases to catch and detect are a result of the wrong evaluation mode. I don't think we should switch any defaults either, that may have wide spread consequences. I also don't think parsing the hashbang is a good idea, feels like it's just hijacking something we don't control. Magic comments are pretty common way to solve this problem across languages. C has Spiritually they're very similar to Elixir's One thing I keep coming back to is that the eval mode, to me, feels like a concern of the script author, not the script runner. Therefore, however it is articulated in the script (shebang, magic comment, But ya, once again I want to make clear, even if folks disagree with that perspective, it's not a show stopper for me. A CLI flag (scriptable via a shebang) technically solves my personal problems. |
At first I was not sure what to think about it, but that's actually very interesting idea! Please pay attention that it would not be "just" documented, but it would also be supported out-of-box by any editor/plugin that shows documentation. This is important especially because even if editor/plugin would parse hashbang it would not recognise every option passed to every possible executable and because of that I like this solution the most. ❤️ |
Unfortunately, hashbangs don't work on Windows, so we have to rule it out as an option. Error messages are also trickly because we never have the whole context. It could also happen that the script author wrote a typo,
I think this could be a good direction, but it should not be a special module+function hardcoded in the compiler. The only times we hardcode things in the compiler are for optimizations, not for semantics. Furthermore, we need to be clear that whatever this is, it must only happen at the top of the file, before any other expression. A similar solution is to introduce a special form called pragma:
However, solutions in this style have a downside. The reason why pragmas are typically magic comments is because pragmas must be parsed before the contents of the file are parsed. This is not strictly the case for this feature, this feature requires configuring compilation/evaluation after the code is parsed, but there is a chance that we will need an actual pragma in the future, and this approach will either close the door on that or force us to have two somewhat overlapping solutions. For example, we could use pragmas/magic-comments to opt-in to some Unicode features. |
If the concern is documentation, which is definitely a good concern, I am sure we could teach editors to display something. We could even choose a more specific syntax so it is easier to spot
or
|
If we are going the pragma route, I think the syntax '# @pragma: eval-expr' makes more sense to me. The one with the elixir word would only make sense if we could colide with other pragmas? But that can't happen in an .exs file. |
# elixir-mode:
to .exs
files to enable Mix.install/imports in same file.# elixir-mode:
to .exs
files to enable Mix.install/imports in same file
@thmsmlr just so you know, in Livebook we are telling users to run it as |
Hardcoding seems like an interesting solution, but as I understand it would break if we complicate the example a little: module = Code
module.mode(:eval_expr) It's not like there's a compelling reason for a user to do such shenanigans, but I don't like an idea of introducing an obscure rule under which a seemingly regular code behaves in an unexpected way. If that is the case, my vote is for a magical comment. |
Elixir and Erlang/OTP versions
Erlang/OTP 27 [erts-15.0.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]
Elixir 1.17.2 (compiled with Erlang/OTP 27)
Operating system
MacOS
Current behavior
Currently, when writing Elixir Scripts, if you Mix.install a dependency and try to import it in the same file at the top-level it doesn't work (see issues).
This happens because the default execution mode for elixir scripts is to compile the entire file and run. Whereas if the script was run expression at a time, like if you were to run
Mix.install()
thenimport
in an IEX shell, you'd get the desired behavior.This rears its head in other situations too, for example, you can't define a struct and use it in top-level in the same elixir script either.
This feels like something you'd really want to be able to do in a scripting environment, especially now with Mix.install and projects like Livescript, or Livebook when exporting to .exs
What's interesting is that this has already been addressed in IEX when using a
~/.iex.exs
file to solve exactly this (See commit). Notably, however it is only for~/.iex.exs
files and not for files passed into IEX as a CLI argument.Expected behavior
Based on a conversation with @josevalim on X. A solution could be to add a
# elixir-mode:
pragma to elixir scripts that allows the user to define how the script should be executed.When scripts are put into
# elixir-mode: expr-eval
mode, the script will be evaluated expression by expressions allowing for things like Mix.install & import to be used within the same script. As well as using structs top-level that were defined in the same file.The text was updated successfully, but these errors were encountered: