Scala、Maven 和预处理器

发布于 2024-09-12 14:23:41 字数 376 浏览 7 评论 0原文

我知道所有反对 Java 中的预处理器和宏的哲学论证。我不同意仅仅因为某些人可能滥用某种语言功能,就应该将其排除在外。

我想在 Java 和 Scala 代码中包含 __FILE____LINE__ 宏,以实现高效日志记录。由于运行时性能影响,任何异常的使用都是不可接受的。那些认为可以在“生产代码”中关闭日志记录的人应该听取 Brian Kernighan 的建议:

删除“现在程序正在运行”的错误消息就像在地面上戴着降落伞,但一旦在空中就将其脱下。

这些宏是否有可能进入该语言?如果没有,有没有办法使用 Maven 运行像 m4 这样的预处理器?

谢谢。

I know all of the philosophical arguments against preprocessors and macros in Java. I don't agree that just because some may abuse a language feature, it should be excluded for all.

I would like to include __FILE__ and __LINE__ macros in my Java and Scala code for efficient logging. Any use of Exception is unacceptable because of runtime performance impacts. Those people who argue that logging can be turned off in "production code" should heed the advise of Brian Kernighan:

Removing the error messages "now that the program is working" is like wearing a parachute on the ground, but taking it off once you're in the air.

Is there any possibility that these macros might make it into the language? If not, is there any way to run a preprocessor like m4 using Maven?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

暖树树初阳… 2024-09-19 14:23:41

更新
@拉尔夫
嗯,这是 2 多年前的问题,但由于我对 __LINE__ 和 __FILE__ 有同样的需求,并且您提到了 SCALA;以下是我使用 Scala 宏(从 v2.10.0-RC1 开始)的一些想法,

def $currentPosition:String = macro _currentPosition;
def _currentPosition(c:Context):c.Expr[String]={ import c.universe._;
  val pos = c.enclosingPosition;
  c.Expr(Literal(Constant(
    s"${pos.source.path}: line ${pos.line}, column ${pos.column}" )))
}

编译时评估宏,$currentPosition 被替换为描述其在源代码中位置的文字字符串。例如,在第 13 行放入一个 println ,它会显示:

/sandbox/tmp_juno_workspace2/LogMacro_Test/src/test/Trial.scala: line 13, column 15

我没有广泛使用这些机制,但是通过调整这个东西,人们可以开发他需要的日志记录功能(我应该补充一点,编写宏可能很困难 - 这对我来说!)。

Update
@ralph
Well, this is a question from 2+ years ago, but since I'm having the same need for __LINE__ and __FILE__ and you had mentioned SCALA; here are some ideas I'm having, using Scala macros (as of v2.10.0-RC1)

def $currentPosition:String = macro _currentPosition;
def _currentPosition(c:Context):c.Expr[String]={ import c.universe._;
  val pos = c.enclosingPosition;
  c.Expr(Literal(Constant(
    s"${pos.source.path}: line ${pos.line}, column ${pos.column}" )))
}

Macros being evaluated at compile-time, $currentPosition is replaced with a literal string that describes its position in the source code. For example, put in a println at line 13, it displays:

/sandbox/tmp_juno_workspace2/LogMacro_Test/src/test/Trial.scala: line 13, column 15

I have not played with these mechanisms extensively, but by tweaking the thing, one can develop the logging features (s)he requires (I should add that writing macros can be difficult - it is for me!).

夏の忆 2024-09-19 14:23:41

恕我直言,实现这一点的“正确”方法是编写一个编译器插件来执行替换,但这真的值得付出这么多努力吗?

IMHO the "correct" way to achieve this would be to write a compiler plugin to perform the substitution, but is it really worth that amount of effort?

凡尘雨 2024-09-19 14:23:41

无论如何,日志记录应该是一个跨领域的问题。可以用方面来做你想做的事情。

Logging should be a cross-cutting concern, anyway. It's possible to do what you want with aspects.

月亮是我掰弯的 2024-09-19 14:23:41

您可以使用编译器 API 来执行此操作,但要小心。注释处理器/编译器插件的“规则”规定它们不应修改正在生成的类。 Sun/Oracle 可以随时强制执行此规定。

现在,请访问 http://projectlombok.org。它使用编译器 API 来生成 getter、setter 等。它们有源代码,您可以将其用作模型,或者您可以为它们提供处理程序。

您可能可以执行如下操作:

public class Foo {
  @FileName private static String fileName;
  @LineNumber private static int lineNumber;
  ...
  public void foo() {
     log(fileName, lineNumber, "some message");
  }
}

然后让注释处理器将 fileName 和 lineNumber 引用更改为实际文件/行。

请注意,这可能会在更高版本的 JDK 中出现问题。我不知道 Sun/Oracle 是否会真正执行“不要修改正在生成的类”规则,但他们可以。

You can use the compiler API to do this, but be careful. The "rules" for annotation processors/compiler plugins state that they are not supposed to modify the class being generated. Sun/Oracle may enforce this at anytime.

For now, have a peek at http://projectlombok.org. It uses the compiler API to generate getters, setters and so forth. They have source code that you could use as a model, or you could contribute handlers to them.

you could probably do something like the following:

public class Foo {
  @FileName private static String fileName;
  @LineNumber private static int lineNumber;
  ...
  public void foo() {
     log(fileName, lineNumber, "some message");
  }
}

Then have the annotation processor change the fileName and lineNumber references to the actual file/line.

Just be aware that this could break with later JDK versions. I don't know if Sun/Oracle will actually enforce the "don't modify the class being generated" rule, but they could.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文