When (if ever) is it okay to use whitespace / indentation in CMake generator expressions? - cmake

The CMake documentation on generator expressions is fairly clear that "A common mistake is to try to split a generator expression across multiple lines with indenting". Here is the example they give:
# WRONG: New lines and spaces all treated as argument separators, so the
# generator expression is split and not recognized correctly.
target_compile_definitions(tgt PRIVATE
$<$<AND:
$<CXX_COMPILER_ID:GNU>,
$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,5>
>:HAVE_5_OR_LATER>
)
My experience is that using multiple lines with indenting works exactly as I'd hope. For example, the following code produces the exact results I would naively expect with the use of whitespace and indentation:
target_compile_options(common_interface INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:
/W4 # Turn on warnings
/WX # Turn warnings into errors
>
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:
-Wall # Turn on warnings
-Wextra # Turn on warnings
-Werror # Turn warnings into errors
>
)
As I understand the CMake documentation, each line here would be added as a separate compile option (e.g., $<$<CXX_COMPILER_ID:MSVC>:), but that is clearly not the case since the generated build files show the flags come through correctly.
My questions are:
What am I missing? Is the issue only with certain types of expressions (e.g., logical operators)? Has the behavior changed and the documentation is out of date? or maybe the documentation needs to be enhanced to clarify the restrictions and expected behavior?
Is it safe to continue using whitespace and indentation in some circumstances?
My suspicion is that the resulting true_string (or false_string in $<IF:condition,true_string,false_string>) of a conditional expression may contain whitespace, but the other arguments of an expression cannot be broken.

Tsyvarev's comments to the question are on the money, but I'll give a more formal answer as both one of the CMake maintainers and the author of the generator expression documentation you linked to. The TLDR version is "The docs describe what you can rely on. Don't rely on implementation details that are outside that and which may change.".
The documentation makes clear where you are required to use quoting to ensure robust behavior. Splitting a genex across multiple lines or whitespace has never been officially supported. Sometimes it might appear to work, but that is by coincidence, not by design. Just because you found a case that happens to work in some range of CMake versions, you shouldn't assume that is supported behavior, especially when the documentation now explicitly calls that out as unsupported. There is no promise that such unsupported behavior will continue to work in future releases.
To be absolutely clear, the direct answers to your questions are:
What am I missing? Is the issue only with certain types of expressions (e.g., logical operators)? Has the behavior changed and the documentation is out of date? or maybe the documentation needs to be enhanced to clarify the restrictions and expected behavior?
The documentation is up to date, and I don't know how to make things clearer than what the existing documentation already says. You're asking about things that go directly against that documentation. The aspects you're asking about are not things we intend to document because they are specifically not intended to be supported behavior! Furthermore, CMake's behavior in this area may well have changed over different versions, but it has never been promised to be stable, since it has never been part of CMake's documented API.
Is it safe to continue using whitespace and indentation in some circumstances?
No. The current documentation should make it very clear what's safe and what isn't. If you're asking if something that contradicts that documentation is safe, well, it should hopefully be clear that my answer is still "No". ;)
Footnote
People failing to quote their generator expressions has been one of the most frequently reported problems (or more accurately, the cause of reported problems) in the CMake forums and issue tracker. It kept biting people over and over, to the point where I wrote a Quoting In CMake blog article about quoting in general and I also added the Whitespace And Quoting section to the generator expressions manual in the official CMake docs (that update appeared with CMake 3.24).

Related

Useless use of LOOP_BLOCK_1 symbol in sink context

With a snippet like
perl6 -e 'loop { FIRST say "foo"; last }'
I get
WARNINGS for -e:
Useless use of LOOP_BLOCK_1 symbol in sink context (line 1)
foo
I know how to work around the warning. I'm wondering about what the source of the warning is. I found this open ticket, but it doesn't seem to have received any attention.
What is this warning about?
And what about this is useless?
Version
$ perl6 --version
This is Rakudo version 2018.06 built on MoarVM version 2018.06
implementing Perl 6.c.
It's a bug, a bogus warning.
I know how to work around the warning.
That's the main thing.
I'm wondering about what the source of the warning is.
It's a bogus warning from the compiler.
I found this open ticket, but it doesn't seem to have received any attention.
I think it got some attention.
bbkr, who filed the bug, linked to another bug in which they showed their workaround. (It's not adding do but rather removing the FIRST phaser and putting the associated statement outside of the loop just before it.)
If you follow the other links in bbkr's original bug you'll arrive at another bug explaining that the general "unwanted" mechanism needs to be cleaned up. I imagine available round tuits are focused on bigger fish such as this overall mechanism.
Hopefully you can see that it's just a bizarre warning message and a minor nuisance in the bigger scheme of things. It appears to come up if you use the FIRST phaser in a loop construct. It's got the very obvious work around which you presumably know and bbkr showed.
What is this warning about?
Many languages allow you to mix procedural and functional paradigms. Procedural code is run for its side effects. Functional code for its result. Some constructs can do both.
But what if you use a construct that's normally used with the intent of its result being used, and the compiler knows that, but it also knows it's been used in a context in which its value will be ignored?
Perls call this "useless use of ... in sink context" and generally warn the coder about it. ("sink" is an alternative/traditional term for what is often called "void" context in other language cultures.)
This error message is one of these warnings, albeit a bogus one.
And what about this is useless?
Nothing.
The related compiler warning mechanism has gotten confused.
The "Useless use of ... in sink context" part of the message is generic and hopefully self-explanatory.
But there's no way it should be saying things like "LOOP_BLOCK_1 symbol". That's internal mumbo-jumbo.
It's a warning message bug.

What does `impl` mean in Kotlin?

I didn't find any explanation in the reference, but when I type impl in IntelliJ IDEA, I get an error:
It seems that it's treated as a reserved word, but what's it for?
I tried putting many kinds of stuffs after impl but I get the error every time.
Update: It's renamed to expect after Kotlin 1.2.
It's for future multiplatform project support, and it's the pair of the header keyword which #hotkey explained in their comment here. It appeared in one of Andrey Breslav's presentations which you can find here, this specific topic starts at the 14:25 mark.
To sum it up briefly, the basic idea he presents is that you could have a common module shared between your platforms, in which there are some functions that are declared but not implemented, and are marked with the header keyword. Then, for the different platforms (JVM, JS, etc) you could have separate modules that implement these functions in platform specific ways - these actual implementations are where the impl keyword would be used.
He says that this whole system is just an internal prototype for now, so this presentation is probably all the public info we have about it. I'd also be interested in more details about this mechanism though :)
Update: as of the Kotlin 1.2 Beta, these keywords have been now replaced with expect and actual.

Problems with Code in the Frege REPL

While trying to learn Frege I copied some code from Dierk's Real World Frege to the online REPL an tried to execute it (see also How to execute a compiled code snipped in Frege online repl). The scripts I've tried don't compile :-(
What am I doing wrong?
Here are examples of what does not compile:
println ( 2 *-3 ) -- unlike haskell, this will work!
and the whole ValuesAndVariables.fr code
It is unavoidable that over the course of more than a year, an evolving language (and its libraries) change so that older code will not compile anymore.
It would be nice, if we could see an example, instead of a generalization like "most".
The next best thing would be to have an issue in Dierks project that points to the error(s).
But the very best would be en effort to find out what is wrong. This would also intensify your learning process.
Here are two ressources that could help:
https://github.com/Frege/frege/wiki/New-or-Changed-Features -- the release notes for every release, contains a summary of things that have changed between releases, and especially the reasons why code would not compile anymore and how to correct it.
http://www.frege-lang.org/doc/fregedoc.html -- the library docs. May explain possible errors like import not found, or missing identifiers.
Go, give it a try. And I'm convinced Dierk will be happy to accept pull requests.
Edit: Fixes for announced errors.
The error in:
println ( 2 *-3 )
stems indeed from a syntactical change.
It is, as of recently, demanded that adjacent operators be separated by at least one space.
Hence
println (2 * -3)
However, the error message you got here was:
can't resolve `*-`, did you mean `-` perhaps?
which could have triggered the idea that it tries to interpret *- as a single operator.
The other error in ValuesAndVariables1.fr is indeed a show stopper for a beginner. The background is that we have one pi that has type Double and one that has type Float and potentially many more through type class Floating, so one needs to tell which one to print.
The following will work:
import Prelude.Math -- unless already imported
println Float.pi
println (pi :: Double)
the online REPL at http://try.frege-lang.org is currently based on Frege V3.23.370-g898bc8c . Dierk's code examples are based on V3.21.500-g88270a0 (which can be seen in the gradle build file).
It seems that the Frege developers decided to change the Frege syntax slightly between those versions. THe result is that you will not be able to run these code snippets in the online REPL anymore.

Elixir: lint for confirming that every function has type sepcification

Is there a lint for Elixir (like for Javascript) which checks that every function has a type specification?
There is an Erlang compiler switch, +warn_missing_spec, which does this, but I'm having trouble getting it to work with Elixir at the moment, I think there is a bug with it's parsing of the ELIXIR_ERL_OPTS environment variable which is converting +warn_missing_spec into -warn_missing_spec which isn't a valid compiler option. I'm going to open an issue on the tracker, but thought you might like to know that this does indeed exist.
EDIT: As José mentioned below, the correct flag is ERL_COMPILER_OPTIONS. You can enable the missing spec warning during compilation by doing the following:
ERL_COMPILER_OPTIONS="warn_missing_spec" mix compile
Keep in mind you may get superfluous warnings from Elixir itself, for functions like __MODULE__. It should still be useful though. One last thing to note, I discovered this morning that there is a problem using this flag with mix compile, and that it's currently only warning about mix.exs. This is being fixed, and may even be fixed by the time you see this, but it's something to be aware of.

Say I didn't like the syntax of objC blocks... (or: how to customize llvm a little bit)

...is there anything I could do about it?
To be more precise, I would like to replace the caret "^" with something like "§" - granted, there's not much left on the keyboard that's not in use already.
After thinking about it for a while (dismissed using run script build phases along the way) I think the only way to do it would be a custom llvm build.
While I don't quite think I'm ready to deal with the internals of compilers, I have the naive hope that replacing one symbol with another isn't too hard. And the idea of building and running my own version of a compiler tickles me, be it just for a good deal of childish fun.
So I started poking around in the llvm sources, but - surprise - got nowhere so far.
If someone is familiar with these kind of things, could you please point me to a place to look at?
That would be awesome! Thanks!
Extending LLVM can be a bit of a hassle, especially considering how fast-moving the compiler team is, so it's a good thing you don't have to. The C preprocessor exists to perform the exact same thing you've outlined (text replacement). I'm fairly sure § isn't aliased to anything important, so #define § ^ should work great. If you still want to write your own module, LLVM provides instructions on how to extend their compiler.
Actually the code relevant for such a change isn't a part of LLVM at all, but a part of its Objective-C frontend, called Clang. Confusingly, "Clang" is also the name of the entire C/C++/ObjC compiler based on both Clang and LLVM.
While I don't quite think I'm ready to deal with the internals of compilers, I have the naive hope that replacing one symbol with another isn't too hard.
And you'll be right. What you're trying to do is very simple change.
In fact, if ^ was only used for blocks, it would be a trivial change - just modify the lexer to generate the "caret" token from § instead of ^: take a look at the lexer code to see what I mean (search for ^).
Unfortunately it's used for xor as well, so we'll have to modify both the lexer and the parser. The lexer to add a new token type and create that token from §, the parser to actually do something with it, e.g. by adding:
case tok::section: // 'section' is the token type you've added
Res = ParseBlockLiteralExpression();
break;
(and then fixing the assert at the beginning of ParseBlockLiteralExpression()).
You might run into some issues, though, as § isn't in ASCII - though as far as I know Clang should be able to deal with UTF-8 encoded files.