News for hackers. Stuff that matters.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @03:39PM (#28029184)
Anytime macros are used for metaprogramming, it's time to reach for a more powerful language.
Re:Learning that you can use unions in C for grouping things... by tpoacher on Monday August 02, 2021 @03:42AM (#28033921)
I hear your quote, but it's only a quote.

A macro is effectively preprocessing facilitated by the language. You could always preprosess externally if you wanted, and there's nothing stopping you from doing that in the "Powerful Language (TM)" either.

Now whether people use macros and preprocessing usefully is another question, but not one to which the answer is "abolish macros for more language features". When used correctly, macros ARE power.

Re:Learning that you can use unions in C for grouping things... by 10000truths on Sunday August 01, 2021 @03:51PM (#28029285)
Macros are useful, as long as they're used sparingly. I think that in this case, it's used well - the struct is still perfectly readable, and the sole purpose of it is to make it so that you don't have to manually name the dummy fields. But you could totally just write out dummy1, dummy2, dummy3 etc. yourself if you want to get rid of the macros.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @06:59PM (#28031018)
> Macros are useful, as long as they're used sparingly.

Everybody says that. Everybody believes it. And everybody goes to town making a rat's nest with macros, just like that snarl of cables under my desk that resist all attempts to make it nice.

Myself included. I've even written an article about clever C macros. Look, ma! I was so proud of myself.

But then I got older. I started replacing the macros in my C code with regular code. It turns out they weren't that necessary at all. I liked the C code a lot better when it didn't have a single # in it other than #include.

Re:Learning that you can use unions in C for grouping things... by throwaway17_17 on Sunday August 01, 2021 @04:53PM (#28029855)
I want to be clear about your meaning, because I don’t know if I’m reading your comment correctly. Are you referring explicitly to syntax based, preprocessor macros? Or does your comment extend to other metaprogramming techniques? I am inclined to think you mean the first considering the amount of emphasis on generic programming in D? Just curious.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @06:51PM (#28030945)
I'm referring to both syntax based (AST) macros, and text based (preprocessor) macros. The latter, of course, are much worse.

An example of the former is so-called "expression templates" in C++. I've seen them used to create a regular expression language using C++ expression templates. The author was quite proud of them, and indeed they were very clever.

However nice the execution, the concept was terrible. There was no way to visually tell that some ordinary code was actually doing regular expressions.

C++ expression templates had their day in the sun, but fortunately they seem to have been thrown onto the trash pile of sounds-like-a-good-idea-but-oops.

(I wrote an article showing how to do expression templates in D, mainly to answer criticisms that D couldn't do it, not because it was a good idea.)

Re:Learning that you can use unions in C for grouping things... by d110af5ccf on Monday August 02, 2021 @01:39AM (#28033250)
> Anytime macros are used for metaprogramming, it's time to reach for a more powerful language.

> I'm referring to both syntax based (AST) macros ...

This surprises me greatly. Various lisps are among the most powerful languages I know of and a large part of the reason is macros coupled with their ability to execute arbitrary code at compile time (which itself uses additional macros, which in turn invoke more code, and so on). What's your take on this?

(Continuations are also pretty nice ...)

Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @03:25AM (#28033821)
I'm a noob when it comes to Lithp. But I'm told what happens with their macros is the language is fairly unusable until you write lots of macros. The macros then become your personal undocumented wacky language, which nobody else is able to use.

I've seen this happen with assembler macro languages, too.

> most powerful

It's like putting a 1000 hp motor in a car. It's main use is to wreck the car and kill the driver.

BTW, D is the first language of its type (curly brace static compilation) to be able to execute arbitrary code at compile time. It started as kind of "let's see what happens if I implement this", and it spawned an explosion of creativity. It has since been adopted by other languages.

Re:Learning that you can use unions in C for grouping things... by d110af5ccf on Monday August 02, 2021 @06:46AM (#28035012)
> the language is fairly unusable until you write lots of macros

This is not (typically) the case. It would be like saying that you need to write lots of templates to get things done in D. Metaprogramming is certainly very nice to have but it's not a requirement for the vast majority of tasks.

It's important to note that Lisps are an entire family of languages; some implementations are batteries included while others are extremely minimal. Where things can get a bit confusing is that many macro implementations are so seamless that significant pieces of core language functionality are built in them. Schemes tend to take this to an extreme, with many constructs that I would consider essential to productive use of the language provided as SRFIs.

> macros then become your personal undocumented wacky language

That's Doing It Wrong™. You could as well argue to remove goto from a language because sometimes people abuse it and write spaghetti. C++ has operator overloading. D has alias this. If (for example) a DSL is the appropriate tool then being able to use macros to integrate it seamlessly into the host language is a good thing.

Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @01:43PM (#28040023)
> it's not a requirement for the vast majority of tasks.

Right, but the temptation to do it is irresistible.

> That's Doing It Wrong™

Of course it's doing it wrong. The point is, that seems to always happen because the temptation is irresistible.

> goto

I rarely see a goto anymore. It just doesn't have the temptation that macros do.

> alias this

Has turned out to be a mistake.

> integrate it seamlessly into the host language is a good thing

Supporting the creation of embedded DSLs is a good thing. Hijacking the syntax of the language to create your own language is a bad thing. I've seen it over and over, it never works out very well. It's one of those things you just have to experience to realize it.

D's support for DSLs comes from its ability to manipulate string literals at compile time, generate new strings, and mixin those strings into the code. This is clearly distinguishable in the source code from ASTs.

Re:Learning that you can use unions in C for grouping things... by d110af5ccf on Monday August 02, 2021 @08:35PM (#28044467)
Fair enough, it seems we have very different philosophies on this particular issue. Without oft maligned features such as alias this and operator overloading I never would have given D a try as an alternative to C++.

I'd like to suggest that I think you might be missing some perspective here. You say that misuse of macros always happens and that you've seen it over and over. Yet if you explore the Scheme ecosystem you might notice that significant parts of any given implementation often take the form of macros. Racket in particular fully embraces the idea of the programmer mixing customized languages together and while examples of bad code certainly exist it seems to work out quite well on the whole.

To be clear, I do appreciate having easy access to tools that are simple and safe. I just also like having seamless access to and interop with a set of powerful ones that don't try to protect me from my own poor decisions. I shouldn't need to do extra work to make use of an alternative more powerful tool for a small part of a project. At that point it becomes very tempting to drop the safer tool altogether in favor of the more powerful one just to avoid the obviously needless and therefore particularly irritating overhead.

I much prefer the approach of providing limited language subsets that can be opted into and out of in a targeted manner. Having the compiler enforce a simple one by default provides a set of guard rails without getting in the way when it matters.

If I could write the majority of my code in something resembling Go and just a small bit of it in an alternative dialect with expressive power comparable to Common Lisp that would be ideal. To that end, I'm a huge fan of features like @system, @safe, and @nogc in D while very much disliking the need to use string mixins to write a DSL, the various restrictions placed on CTFE behavior, and other similar things.

Re:Learning that you can use unions in C for grouping things... by nextaccountic on Monday August 02, 2021 @07:39AM (#28035343)
> BTW, D is the first language of its type (curly brace static compilation) to be able to execute arbitrary code at compile time. It started as kind of "let's see what happens if I implement this", and it spawned an explosion of creativity. It has since been adopted by other languages.

I don't know much about D compile time evaluation. How is it better than macros/templates?

Also, what do you think about Haskell's and Rust's approach of generics with typeclass/trait bounds?

Re:Learning that you can use unions in C for grouping things... by d110af5ccf on Monday August 02, 2021 @08:08AM (#28035542)
> D compile time evaluation. How is it better than macros/templates?

CTFE isn't better than templates, it's a completely different tool. CTFE computes a result at compile time as though you had written a literal in the source code. Templates generate blocks of specialized code on the fly based on various parameters (typically types). They solve different problems.

Re:Learning that you can use unions in C for grouping things... by nextaccountic on Monday August 02, 2021 @02:03PM (#28040341)
I think that Walter was trying to say that D gets by doing the same things that people use macros for, but without macros. I interpreted this as meaning that D uses CTFE in those same situations. Am I wrong?

What does D do, then?

Re:Learning that you can use unions in C for grouping things... by d110af5ccf on Monday August 02, 2021 @09:05PM (#28044633)
I think he was saying that sufficiently powerful languages provide enough features that you won't need macros in the first place. If you feel that you do for some reason, go find a more powerful language instead.

> What does D do, then?

Most mainstream languages, D included, very intentionally don't provide any features that could potentially be used to extend the language itself on the fly. (At least not in a straightforward manner. Obviously the C preprocessor kind of sort of facilitates a bit of this.)

As a counterexample, Rust does provide some of this in the form of procedural macros but doesn't provide (to the best of my knowledge) an equivalent to Lisp reader macros.

Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @01:45PM (#28040045)
I wish you luck with it. If you send me an email, when I find what I wrote about it I'll pass it along to you.
Re:Learning that you can use unions in C for grouping things... by nextaccountic on Monday August 02, 2021 @02:08PM (#28040415)
I think you replied the wrong comment
Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @07:35PM (#28044060)
Oops, indeed I did. Replied to the right one!
Re:Learning that you can use unions in C for grouping things... by shaklee3 on Monday August 02, 2021 @01:10AM (#28033127)
Can you link to it? We're using expression templates on a new library and I find it useful.
Re:Learning that you can use unions in C for grouping things... by acehreli on Tuesday August 03, 2021 @01:01PM (#28051524)
I don't know what code Walter is referring to but I had similar experiences during a presentation of the Boost Spirit library (at our Silicon Valley C++ Meeting; must be about a decade ago now).

The speaker was proud and beaming for showing how powerful C++ is and the audience was in awe.

I was incredulous! Jaw open! The "solution" was horrible with a bunch of workarounds for a bunch of shortcomings. It was a "the emperor does not have cloths" moment for me.

Boost Spirit may be better today with newer C++ features; I don't know.

Re:Learning that you can use unions in C for grouping things... by shaklee3 on Tuesday August 03, 2021 @01:09PM (#28051628)
That's kind of the key. We require c++17. Without that it gets extremely ugly and more verbose.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @03:27AM (#28033835)
Oh man, you sure know how to drive a stake in my heart! What have I done! Some curses should just not be uttered. I'm not sure where it is on my backups.

But it was done just like you'd do it in C++. The same thing, just with D syntax.

Re:Learning that you can use unions in C for grouping things... by shaklee3 on Monday August 02, 2021 @09:11AM (#28036051)
We're making a numerical computing library that expression templates are used for compile-time evaluation of expressions. It's a very niche hpc library, so it might be one of the few places it's appropriate.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @07:35PM (#28044056)
I wish you luck with it. If you send me an email, when I find what I wrote about it I'll pass it along to you.
Re:Learning that you can use unions in C for grouping things... by 1980phipsi on Tuesday August 03, 2021 @01:08PM (#28051618)
They probably aren't the only people interested in that...
Re:Learning that you can use unions in C for grouping things... by Spivak on Sunday August 01, 2021 @04:20PM (#28029520)
Doesn’t work in a lot of cases unfortunately. If you’re writing a library designed to be consumed by other languages you’re stuck with writing C abi compatible code which can be written in other languages that can “extern” them but it puts limits on what’s possible in those libraries.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @11:32PM (#28032604)
One thing I do is to make my own interface to the 3rd party library with the ugly interface. Then that interface file is only one that sees it.

It also may be true that one can't replace every use of the preprocessor. That shouldn't stop replacing what one can.

Re:Learning that you can use unions in C for grouping things... by cryptonector on Sunday August 01, 2021 @06:21PM (#28030704)
You might as well have written that "any time you're reaching for C, it's time to reach for a more powerful language".

But if -sadly- you must use C, metaprogramming using macros is not a terrible thing.

Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @07:07PM (#28031087)
> is not a terrible thing

It is a terrible thing. It's possible to do without them, and you'll like your code better. Your symbolic debugger and syntax directed editor will work properly. The poor schlub who has to fix the bugs in your code after you leave will be grateful. Your spouse will be happy and your children will prosper.

For example,

    #define foo(x) ((x) + 1)
replace with:

    int foo(int x) { return x + 1; }
The compiler will inline it for you. There's no penalty.

    #define FOO 3
Replace with:

    enum { FOO = 3 };
or:

    const int FOO = 3;
Replace:

    #if FOO == 3
    bar();
    #endif
with:

    if (FOO == 3) bar();
The optimizer will delete bar() if FOO is a manifest constant that is not 3.
Re:Learning that you can use unions in C for grouping things... by cryptonector on Sunday August 01, 2021 @10:22PM (#28032250)
Having made a significant contribution to Simon Tatham's PuTTY, I have to respectfully disagree. At the time the entire SSHv2 key exchange and user authentication protocols were implemented in a single function using a massive Duff's device (for asynchrony) implemented with C metaprogramming macros. It was a surprisingly pleasant experience.
Re:Learning that you can use unions in C for grouping things... by pjmlp on Monday August 02, 2021 @03:21AM (#28033801)
There is a reason why such clevernesses are forbiden by security standards like MISRA-C.
Re:Learning that you can use unions in C for grouping things... by zerr on Sunday August 01, 2021 @07:53PM (#28031429)
Agree except the last example - the clarity of intent that you want a conditional compilation is lost. Also, non-optimized debug builds are affected.
Re:Learning that you can use unions in C for grouping things... by CamperBob2 on Sunday August 01, 2021 @08:31PM (#28031628)
I think it was RMS who argued that conditional compilation should be considered harmful in general. Code that you put in an inactive #if(def) block will not be maintained, and is basically guaranteed to rot. If it's needed in the future, it'll likely have to be rewritten from scratch.

According to this stance, any code that's suppressed by the C preprocessor should either be written in an if {} statement so that it will at least continue to compile as the surrounding code changes, or be replaced with comments describing what it does (or did), if it's important enough to keep track of.

Can't really think of many good counterarguments to this. Machine dependence might be one, but then you could argue that the preprocessor is being used to cover up for an inadequate HAL.

Re:Learning that you can use unions in C for grouping things... by zerr on Monday August 02, 2021 @03:41AM (#28033916)
When it comes to cross-platform code, you build for several platforms, so the block is active (for particular platforms) and maintained.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @09:01PM (#28031824)
> clarity of intent

Conditional compilation is an optimization, not a semantic intent.

> non-optimized debug builds are affected

The code size will be larger. Doesn't matter.

Re:Learning that you can use unions in C for grouping things... by jjnoakes on Monday August 02, 2021 @12:57AM (#28033055)
> Conditional compilation is an optimization, not a semantic intent.

Why can't it have semantic intent? I frequently use it for cross-platform adjustments, and those don't usually compile on the defined-away platform.

Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @03:30AM (#28033854)
> those don't usually compile on the defined-away platform

Then you're doing it wrong :-/

All these can be made to work.

P.S. compiling successfully is not the same thing as linking successfully. Think stubs and deciding which files to link together.

Re:Learning that you can use unions in C for grouping things... by zerr on Monday August 02, 2021 @03:46AM (#28033948)
Making it clear in the code itself that something is platform specific is useful as well. Also, I'd say such stubs and extra files would clutter the project.
Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @04:58AM (#28034401)
I tried it your way for years. It's common practice in the industry. I have written and seen plenty of rats' nests of #if and #ifdef snarls so bad one cannot figure out what is being compiled and what isn't without running a just-the-preprocessor pass. It will often #if on the wrong condition, like operating system when it's a CPU dependency.

Rewriting it the way I suggest tends to force a cleanup of all that. You'll like the results.

BTW, if you want to try transitioning to the next level, try getting rid of all the `if` statements, too!

Re:Learning that you can use unions in C for grouping things... by jjnoakes on Monday August 02, 2021 @10:22AM (#28036875)
They can be made to work by introducing stubs for every os/arch/compiler/dependency I support, but that's way more work for dubious gain.

And who is to say I'm doing it wrong? Just because conditional compilation CAN lead to a rat nest doesn't mean it MUST. And if it happens to be well-organized and works as is, there is no problem.

Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @02:03PM (#28040346)
> that's way more work for dubious gain

Oh, have I heard that before. Here's what happens, over the years, to such code:

1. #ifdef's on the wrong feature. For example, #ifdef on operating system for a CPU feature.

2. Overly complex #if expressions, that steadily get worse.

3. Fixing support for X that subtlety breaks F and Q support. It goes unnoticed because your build/test machines are not F and Q.

4. People having no idea what #defines to set on the command line, nor what the ones that are set are doing (if anything).

4. People having no idea how to fold in support for new configurations.

5. Code will #ifdef on predefined macros that have little or no documentation on what they're for or under exactly what circumstances they are set. If the writer even bothered to research that. gcc predefines what, 400 macros?

> Just because conditional compilation CAN lead to a rat nest doesn't mean it MUST.

Jyust yew wite, 'enry 'iggins, jyust yew wite!

Re:Learning that you can use unions in C for grouping things... by jjnoakes on Monday August 02, 2021 @02:33PM (#28040794)
> Here's what happens, over the years, to such code:

Over how many years? Some of my projects are 30+ years old and support a few dozen combinations of OSes, compilers, and architectures, and the method I described hasn't led to a rat's nest yet.

> #ifdef's on the wrong feature. For example, #ifdef on operating system for a CPU feature

Sure, same thing happens when you decide whether to compile in your stubs or not. But if I make a mistake, the code usually won't compile on the configuration in question; if you make a similar mistake, it'll compile with your stub, it might even link, but you'll get odd runtime behavior. Sounds worse.

> Overly complex #if expressions, that steadily get worse

All code gets worse over time and bit rots if you don't maintain it, I don't see things necessarily worse in this area.

> Fixing support for X that subtlety breaks F and Q support. It goes unnoticed because your build/test machines are not F and Q

If you aren't testing on tier one configurations, they shouldn't be tier one. And if a tier three configuration breaks when you do finally get around to testing it, it's tier three, so it gets fixed when it can be and there's no problem. Similar to normal code, I'd say.

> People having no idea what #defines to set on the command line, nor what the ones that are set are doing (if anything) > People having no idea how to fold in support for new configurations

These problems exist for normal code as well. Someone has to own the build configurations, and they have to be maintained, like anything else.

> Code will #ifdef on predefined macros that have little or no documentation on what they're for or under exactly what circumstances they are set. If the writer even bothered to research that. gcc predefines what, 400 macros?

We only use a handful, and they are fairly well documented. But even if they weren't, since the code works on all tier one platforms, we'd know if something was changed out from underneath us because it was underspecified or accidentally relied upon.

But again the same can happen with normal code and system headers, compiler extensions, etc - I don't see why pre-processor macros have to be singled out here.

> Jyust yew wite, 'enry 'iggins, jyust yew wite!

How long?

Re:Learning that you can use unions in C for grouping things... by shultays on Sunday August 01, 2021 @09:36PM (#28032015)

   The optimizer will delete bar() if FOO is a manifest constant that is not 3. 
Yes, but the compiler won't delete it and complain if bar is not defined. if constexpr is not a direct replacement for if macro
Re:Learning that you can use unions in C for grouping things... by WalterBright on Sunday August 01, 2021 @11:28PM (#28032575)
> the compiler won't delete it and complain if bar is not defined

    extern void bar();
will define it to the satisfaction of the compiler. The linker won't complain if the compiler removes the call to it.
Re:Learning that you can use unions in C for grouping things... by shultays on Monday August 02, 2021 @05:27AM (#28034565)
And then you have the issue of not having types. consider this

  void my_bar_class_type::bar(my_bar_type<my_bar_type_2>::my_bar_inside_type paramater);
and you are calling something like

   myObject->bar(mySecondObject.getWhatever());
You have to mock up like everything
Re:Learning that you can use unions in C for grouping things... by WalterBright on Monday August 02, 2021 @02:05PM (#28040371)
Or go up an abstraction layer so the type details are not needed.