简体   繁体   English

在Elixir中打开模块?

[英]Open modules in Elixir?

Ruby has open classes, which are very handy (though reviled by some), and Elixir borrows heavily from Ruby, so I expected Elixir to allow me to reopen a module and add macros to it after having closed it, but this did not work in the way I tried it. Ruby有开放的类,非常方便(虽然受到一些人的谴责),Elixir大量借用Ruby,所以我希望Elixir允许我重新打开一个模块并在关闭后添加宏,但这不起作用我试过的方式。 Is there some way to do this? 有办法做到这一点吗? Is this feature available yet in Elixir? Elixir中是否提供此功能?

To make this concrete, let's take an example from Chris McCord's Metaprogramming Elixir: 为了具体化,让我们以Chris McCord的Metaprogramming Elixir为例:

defmodule Math do
  defmacro say({:+, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs + rhs
      IO.puts "#{lhs} plus #{rhs} is #{result}"
      result
    end
  end

  defmacro say({:*, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs * rhs
      IO.puts "#{lhs} times #{rhs} is #{result}" 
      result
    end 
  end
end

If I then add a macro for subtraction 如果我然后添加一个宏用于减法

defmodule Math do
  defmacro say({:-, _, [lhs, rhs]}) do
    quote do
      lhs    = unquote(lhs)
      rhs    = unquote(rhs)
      result = lhs - rhs
      IO.puts "#{lhs} minus #{rhs} is #{result}"
      result
    end
  end
end

I get a warning that I'm redefining module Math, and the initially defined macros fail. 我得到一个警告,我正在重新定义模块Math,并且最初定义的宏会失败。 So obviously my approach is not the right one, but is there another approach that can accomplish the same goal? 显然我的方法不是正确的方法,但是有另一种方法可以实现同样的目标吗?

You cannot re-open a module. 您无法重新打开模块。 Since Elixir is a compiled language, the way from source code to an executable representation is one-way. 由于Elixir是一种编译语言,从源代码到可执行表示的方式是单向的。 The mechanisms that alter code, such as macros, are evaluated during compilation time. 在编译期间会评估更改代码的机制,例如宏。 However, Elixir allows you to do hot code swapping, ie you can replace a compiled module during runtime. 但是,Elixir允许您进行热代码交换,即您可以在运行时替换已编译的模块。

I think this has some interesting implications. 我认为这有一些有趣的含义。 You get the ability to change the program at runtime – in practice, you control the source code and so you can swap out individual parts of a module without changing others. 您可以在运行时更改程序 - 实际上,您可以控制源代码,这样您就可以更换模块的各个部分而无需更改其他部分。 Still, I like the idea of having everything in one place. 不过,我喜欢把所有东西放在一个地方的想法。 In Elixir, when you look at a module you know exactly what you've got*. 在Elixir中,当你看一个模块时,你确切地知道你有什么*。

So if this question is only about a convenient development workflow – the closest you will come to Ruby's ability to add methods to a class is to save your module in a file and re-compile it from iex as you go. 因此,如果这个问题仅仅是关于一个方便的开发工作流程 - 最接近Ruby的方法是将类添加到类中的方法是将模块保存在文件中并随时从iex重新编译它。


* Strictly speaking, you might not know exactly what code is running by just looking at a module. *严格来说,只需查看模块,您可能无法确切知道正在运行的代码。 When you are using protocols, you kind of need to look at all of the protocol implementations as well, which may be scattered throughout your codebase, or, even worse, they may be distributed across multiple applications. 当您使用协议时,您还需要查看所有协议实现,这些实现可能分散在整个代码库中,或者更糟糕的是,它们可能分布在多个应用程序中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM