News for hackers. Stuff that matters.
Re:“Modern” C++ Lamentations by tpush on Friday December 28, 2018 @12:42PM (#18778178)
The statement that I found most powerful:

> Compile time of this really simple example takes 2.85 seconds longer than the “simple C++” version.

> Lest you think that “under 3 seconds” is a short time – it’s absolutely not. In 3 seconds, a modern CPU can do a gajillion operations. For example, the time it takes for clang to compile a full actual database engine (SQLite) in Debug build, with all 220 thousand lines of code, is 0.9 seconds on my machine. In which world is it okay to compile a trivial 5-line example three times slower than a full database engine?!

Re:“Modern” C++ Lamentations by leggomylibro on Friday December 28, 2018 @01:20PM (#18778433)
In many ways the '++' in 'C++' comes from giving the compiler more information to work with. You can opt to trust the compiler much more than in C, and the idea is that you gain time at develop-time and hopefully run-time with the tradeoff of losing it at compile-time.

At least, that's how I've usually understood it. And the example you mention seems like a complaint with C++20's Ranges in particular. I guess I'd fall into the, "but can't you just ignore the parts you don't like?" camp.

This post is written in the context of game engines, but I see a lot of the same 'OG C' arguments made when people in embedded development resist giving C++ a try.

We're all writing resource-constrained applications that work on tight time budgets, and none of us feel comfortable throwing up our hands and 'trusting the compiler' in that sort of atmosphere. But C isn't getting any younger, and it's hard to do polymorphism without getting hack-y.

Now, who's turn is it to advocate Rust?

Re:“Modern” C++ Lamentations by blattimwind on Friday December 28, 2018 @02:57PM (#18779021)
> At least, that's how I've usually understood it. And the example you mention seems like a complaint with C++20's Ranges in particular. I guess I'd fall into the, "but can't you just ignore the parts you don't like?" camp.

The issue is that many libraries (including std/stl) tend to produce long compile times.

Re:“Modern” C++ Lamentations by arka2147483647 on Friday December 28, 2018 @02:35PM (#18778880)
> You can opt to trust the compiler much more than in C,

I feel that in modern C++ modern style ”trust the compiler” often means ”leave the programmer out of the loop”

I really, really would hate to have to try to debug the ranges example, for example.

Re:“Modern” C++ Lamentations by lambda on Friday December 28, 2018 @08:39PM (#18781113)
Here's an implementation that is equivalent to the modern C++ example (playground link: https://play.rust-lang.org/?version=stable&mode=release&edit...):

  use std::time::SystemTime;

  fn main() -> Result<(), Box<dyn std::error::Error>> {
      let t0 = SystemTime::now();

      let triples = (1..).flat_map(|z|
          (1..=z).flat_map(move |x| 
              (x..=z).filter_map(move |y|
                  if x * x + y * y == z * z {
                      Some((x, y, z))
                  } else {
                      None
                  }
              )
          )
      );
    
      for triple in triples.take(100) {
          println!("{:?}", triple);
      }
    
      let elapsed = t0.elapsed()?;
    
      println!(
          "{}", 
          elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
      );
    
      Ok(())
  }
It takes about .376s to compile in debug mode, about 0.491s in release mode. This was after warming caches; the first run took about 2.071s, of which a large portion was probably loading the compiler and standard library.

In debug mode, it runs in 0.047586s, in release mode, 0.002304.

I was pleasantly surprised to see this is actually better on the build times and debug build performance, given that those are two often cited sore points in Rust.

I would also say that while this is a little bit noisy, it is more readable than the proposed C++20 version. "1.." looks more like a range starting at 1 than "iota(1)" does. There's an actual "if" statement in there.

In fact, while Rust doesn't officially have generator/coroutine support yet, it is available in nightly builds for the implementation of async/await. If you use the nightly compiler, enable the unstable features, and wrap an adapter type around Generator that implements Iterator, you can write:

    let triples = IterGen(||
        for z in 1.. {
            for x in 1..=z {
                for y in x..=z {
                    if x*x + y*y == z*z {
                        yield (x, y, z)
                    }
                }
            }
        }
    );
It's expected that at some point in the coming year or so async/await, and probably the underlying Generator feature, will be stabilized, and I presume the standard library will implement the Iterator trait for appropriate types of Generators (though there is some bikeshedding about the details of that).

Rust doesn't have generators yet, so this is only really fair to compare to the generator/co_yield example in C++ (which is also proposed but not yet standardized). I'd say Rust's syntax compares favorably to that example; the ranges are more clear than the traditional C-style "for" loops, there's native tuple syntax, and it's just be "yield" instead of "co_yield".

Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @03:25AM (#18782632)
Rust sore points regarding compile times have to do with lack of support for binary libraries.

While on C++ I can take advantage of incremental compilation and linking, while using binary libraries for all dependencies, with cargo I have always to build the whole world from scratch minus standard library.

Re:“Modern” C++ Lamentations by kodemizer on Saturday December 29, 2018 @03:32AM (#18782651)
I'm not sure when the last time you've used Rust is, but that hasn't been true in quite a while (not sure how long exactly). Cargo now has incremental compilation, and it's turned on by default. It's great!
Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @03:51AM (#18782712)
I dabble on Rust regularly, usually during plane or train trips.

It still doesn't do incremental linking, and cargo still builds everything from scratch without any support for binary libraries.

Re:“Modern” C++ Lamentations by kzrdude on Saturday December 29, 2018 @08:28AM (#18783469)
Binary libraries don't help so much -- many libraries use generic types and functions (those are instantiated and compiled for each specific instance) which can only be delivered as library "metadata", not codegen'ed, and the latter is the very slow part.
Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @09:06AM (#18783587)
Wrong since C++11 introduced external templates for common instatiation types.

Additionally, it is not like every C++ library is full of meta-programming templates.

Finally, there are other languages with library "metadata" and generic data types, which can easily beat Rust compile times like Delphi, Eiffel and Ada.

Re:“Modern” C++ Lamentations by pcwalton on Monday December 31, 2018 @06:55PM (#18797930)
Delphi and Eiffel compilers don't do anywhere near the same level of optimization as LLVM does.

And are you sure GCC's Ada has better compile times? My sense is that so few people use Ada at scale that we don't really know.

Re:“Modern” C++ Lamentations by swsieber on Friday December 28, 2018 @02:18PM (#18778801)
Me! Sort of.

Rust is definitely further along the scale towards the end of "giving more to the compiler so it takes longer". I usually like the trade. Most of the time.

Re:“Modern” C++ Lamentations by adrianN on Friday December 28, 2018 @03:47PM (#18779301)
Rust also has a saner module system that makes incremental builds much quicker. They're still pretty slow, but not as agonizingly slow as a clean build.
Re:“Modern” C++ Lamentations by nicoburns on Friday December 28, 2018 @05:22PM (#18779958)
Rust is only fast compared to C++ (and then only sometimes). Literally every other language is significantly faster to compile. I'm hoping this can change though. Rust with fast compile times and a more complete library ecosystem (and ideally better IDE support) would be an incredibly productive language.
Re:“Modern” C++ Lamentations by dzdt on Friday December 28, 2018 @06:40PM (#18780409)
Scala is slower to compile than C++ in large scale enterprise development. (The exception that proves the rule?)
Re:“Modern” C++ Lamentations by nicoburns on Saturday December 29, 2018 @09:34AM (#18783728)
Ah, I forgot about Scala. Someone below mentioned Haskell too (which I haven't used). Still, calling Rust fast seems wrong to me!
Re:“Modern” C++ Lamentations by aphexairlines on Friday December 28, 2018 @08:16PM (#18780985)
Compared with C++, Scala projects are not slow to compile when you use Gradle multi-project builds (with granular sub-projects) and Gradle build caching.
Re:“Modern” C++ Lamentations by swsieber on Saturday December 29, 2018 @12:16AM (#18782010)
Not as agonizingly slow, but still agonizingly slow.

While I do appreciate build speed improvements, saying that it's better than it was isn't a super high bar in terms of user experience.

I love Rust, I really do, but it's still incredibly slow. I'm excited for any progress it makes on this front.

Re:“Modern” C++ Lamentations by kodemizer on Saturday December 29, 2018 @03:34AM (#18782662)
I think the most promising thing on this front is Cranelift (https://github.com/CraneStation/cranelift). The idea is that, when cranelift is ready, we might use it for debug builds (but still use LLVM for release builds).
Re:“Modern” C++ Lamentations by SomeHacker44 on Friday December 28, 2018 @02:57PM (#18779023)
I was an early user of the language in the 80s and early 90s (with for example cfront which compiled to C and later the original g++ and its libg++).

> In many ways the '++' in 'C++' comes from giving the compiler more information to work with.

This is definitely not the origin of the '++'. I believe the '++' name was literally a play about "one better than C."

Re:“Modern” C++ Lamentations by praptak on Friday December 28, 2018 @03:10PM (#18779091)
I remember Turbo Pascal 5.0 and its imperceptible delays between pressing F5 and seeing the program output. I hope some day we can have this in C++, even if it takes sorcery like speculative compilation as-you-type done on a gigawatt cluster of custom chips...
Re:“Modern” C++ Lamentations by int_19h on Friday December 28, 2018 @05:12PM (#18779884)
Pascal (and the entire family - Modula etc) is a language designed by a guy with an academic background in PLs. This shows in the design: e.g. the syntax is verbose and has a very rigid structure, which can often be frustrating to the user (like the need to declare all variables in a separate declaration block at the beginning of each function), but which makes it extremely easy to parse with just a single token lookahead. Similarly, the semantics are such that they're easy for a compiler to implement.

Borland still did a great job with their implementation performance-wise, and the legendary reputation of their Pascal compilers is well-deserved. But they had a solid foundation to build on in form of a tool-friendly language, which C++ just doesn't offer.

Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @03:28AM (#18782640)
Those rules are quite relaxed in Delphi, while still keeping the compilation speed.

Same applies to C++ Builder, at least until they decided to move to clang.

Re:“Modern” C++ Lamentations by int_19h on Saturday December 29, 2018 @07:06PM (#18786485)
By now I think parsing is not exactly the bottleneck. But back in 90s, I'm sure that it has been a part of why TP and BP were as fast as they were, esp. compared to C++. Having precompiled units (and therefore no need to #include hundreds of kilobytes of headers for every translation unit) is probably a bigger deal today.

Also, IIRC Delphi had only recently gotten generics, and they're still not heavily used? I suspect that code that's heavy on those will compile pretty slow.

Re:“Modern” C++ Lamentations by Koshkin on Friday December 28, 2018 @04:55PM (#18779766)
I have seen a modern Oberon compiler building itself in 1/10-th of a second. (The Tiny C compiler does not take much longer, either.)
Re:“Modern” C++ Lamentations by roman_g on Friday December 28, 2018 @06:31PM (#18780354)
It was one of Pascal main features in tape drive era: single pass compiler.
Re:“Modern” C++ Lamentations by userbinator on Friday December 28, 2018 @01:36PM (#18778536)
The size comparisons are also very useful, if anything to show that even the simple "non-Modern" C++ program already has quite a bit of bloat.

Compilation takes 0.064 seconds, produces 8480 byte executable

I am experienced with Asm so I can come up with an instinctive order-of-magnitude estimate, but even those who aren't should try to roughly estimate how many machine instructions are required to implement that code, and come to the conclusion that over 8000 bytes for three nested loops with not much in them, a comparison, some arithmetic, and a handful of library function calls seems rather excessive. Even 800 would be on the high side --- somewhere around 100-200 bytes is my estimate.

Also, watch this 4k demo (everything you see and hear is generated in realtime by a 4096-byte executable):

https://www.youtube.com/watch?v=jB0vBmiTr6o

Re:“Modern” C++ Lamentations by Someone on Friday December 28, 2018 @01:56PM (#18778665)
The 8480 includes bytes used for names of external symbols, etc.

otool tells me the assembly routine is 74 instructions (279 bytes, if I’m counting correctly)

Re:“Modern” C++ Lamentations by jcelerier on Friday December 28, 2018 @01:49PM (#18778614)
I don't think that this is a very meaningful comparison at these sizes, because it entirely depends on your target. Just compiling a "foo.c" file with "int main() { }" for sole content through "gcc -Os" produces a 16kb executable on my linux machine, but I know very well that the exact same compiler will produce something much smaller if I compile for, say, a bare metal AVR target because the ELF file format has a lot of fluff.
Re:“Modern” C++ Lamentations by gumby on Friday December 28, 2018 @03:13PM (#18779110)
> because the ELF file format has a lot of fluff.

I wouldn't call it fluff: even assuming no debugging info (which you won't have in your avr object file) it has info needed at runtime (program start time) such as where to load what into memory, how much initial uninitialised memory to allocate when starting up, etc. It all gets used.

Re:“Modern” C++ Lamentations by bnieuwen on Friday December 28, 2018 @01:54PM (#18778645)
I think the keyword might be an 8k executable, not 8k of code. If I compile the example with clang on my box (linux x86_64) I get a 17K executable, for which the .text section (containing pretty much the runnable code)is 0x291 (661) bytes with the debug build and 0x255 (597) bytes with -O3.

If I dig into the .text segment of the optimized executable, only 235 bytes belong to the main function (others are stuff like __libc_csu_init and register_tm_clones). Looking at the assembly the loop would be about 123 bytes.

So lots of overhead, but I wouldn't say it is in the nested loop.

Re:“Modern” C++ Lamentations by Gibbon1 on Friday December 28, 2018 @03:10PM (#18779096)
I abandoned C++ and Windows programming in 1996 to focus on hardware and firmware. So I'm rather familiar with just straight C and keeping code size down.

You have to be careful, a lot of those 8000 bytes might well be printf().

Re:“Modern” C++ Lamentations by userbinator on Friday December 28, 2018 @04:07PM (#18779415)
You have to be careful, a lot of those 8000 bytes might well be printf().

If it was a statically linked executable, it would be far bigger than 8K.

Re:“Modern” C++ Lamentations by twtw on Friday December 28, 2018 @02:07PM (#18778723)
It's probably a few kilobytes of symbols, a few kilobytes of crt0, some ELF overhead, and a few hundred bytes of user code.
Re:“Modern” C++ Lamentations by Iwan-Zotow on Friday December 28, 2018 @02:38PM (#18778900)
Re:“Modern” C++ Lamentations by zozbot123 on Friday December 28, 2018 @02:02PM (#18778697)
> Compile time of this really simple example takes 2.85 seconds longer than the “simple C++” version.

Haskell, Rust, Scala etc. also have a lot of trouble with compile times. I wonder why, though - is it just a matter of priorities being placed on things other than optimizing the compiler, or is there some actual, inherent complexity in compiling these "modern" languages that doesn't apply to C or Go? (I suspect mostly the former, FWIW).

Re:“Modern” C++ Lamentations by steveklabnik on Friday December 28, 2018 @02:26PM (#18778834)
With Rust, a lot of the issue is monomorphization. Changing one line may make hundreds of lines be needed to recompile. Additionally, we produce more LLVM IR than we must, and rely on LLVM ago boil it away.

It’s a complex set of issues that we’re constantly working on.

(So yes, Go and C do not have generics, and so do not have this problem.)

Re:“Modern” C++ Lamentations by Gibbon1 on Friday December 28, 2018 @03:22PM (#18779159)
Stupid question from a small brained primate.

Would it make sense to have two types of generic implementation with a boxing unboxing mechanism. AKA a fast one that requires a rebuild when you monkey with something. And a slow one that doesn't but compiles fast.

I think it'd be acceptable if the 'dev' version used GC as long as the final build didn't. Basically anyway to get the development cycle to go fast.

Re:“Modern” C++ Lamentations by steveklabnik on Friday December 28, 2018 @03:37PM (#18779231)
Not stupid! You wouldn’t need a GC to do this either. It’s been talked about but nobody has tried to implement it.
Re:“Modern” C++ Lamentations by thechao on Friday December 28, 2018 @04:35PM (#18779632)
Almost like combining Siek’s gradual types with parametric polymorphism: you can search for “gradual parametricity” and find a number of papers on the topic.
Re:“Modern” C++ Lamentations by mpolun on Friday December 28, 2018 @04:25PM (#18779548)
Rust actually has that they just can't be substituted automatically because they're different types:

    fn<T: MyTrait> compile_time(thing: &T) {}
    fn run_time(thing: &dyn MyTrait) {}
The reason that you can't just substitute them is that you can do more with compile-time generics than runtime ones -- runtime generics have unknown size (different concrete types have different size, so what size is the runtime generic version?) so they always have to be used through a pointer (and usually heap allocated). There are a variety of other restrictions on trait objects (runtime generics) for type-system reasons.

It would be possible to find cases where compile time polymorphism is replaced with runtime polymorphism, but I'm not sure it would really gain much given the restrictions.

Now if you start changing the language semantics a lot more becomes possible, but I don't even know what changes you would have to make to the language to let that happen.

Re:“Modern” C++ Lamentations by renox on Sunday December 30, 2018 @03:58AM (#18788187)
That's when Jai (if it ever becomes real) hold promise: fast compilation is a first rate goal, not a second rate goal where you decide language features first then try to make the compiler "not too slow".
Re:“Modern” C++ Lamentations by jules on Friday December 28, 2018 @04:43PM (#18779693)
Do you know what's causing that?

1. Maybe monomorphisation overduplicates code, so that different invocations produce the same machine code in the end?

2. If that's not happening, maybe idiomatic Rust code causes a lot of code to be generated where a C programmer would have written something differently, e.g. using a void* instead of passing by value?

3. If that's not happening either, maybe monomorphisation is more or less producing what a C programmer would have monomorphised manually, but it takes the compiler a long time to optimise away abstractions?

It seems that in this C++ example the problem is #3: it takes a long time to optimise away the range & lambda abstraction.

Re:“Modern” C++ Lamentations by steveklabnik on Friday December 28, 2018 @05:09PM (#18779860)
It’s all three.
Re:“Modern” C++ Lamentations by vmarsy on Friday December 28, 2018 @05:31PM (#18780013)
is monomorphization a more concise term for what is called "implicit template instantiation" in C++?

If so, is Rust worse than C++ when it comes to compile times of those? Heavily templated C++ code is known to be slow to compile due to this. Is it much worse in Rust? Are you aware whether C++ compilers do some special optimizations that Rust compiler doesn't have yet?

I don't see what can be done to make this better, the whole point of templates is to "pay" at compile time for some gains at runtime. (or in this case for gains in the amount of code a developer has to write)

Re:“Modern” C++ Lamentations by steveklabnik on Friday December 28, 2018 @05:38PM (#18780053)
“Monomorphization” is what happens when a template is instantiated. It’s essentially the same thing in both languages, and has roughly the same compiler performance implications.

There’s at least one thing that could be done, in Rust at least. But it’s only in some limited circumstances. See here: http://www.suspectsemantics.com/blog/2016/12/03/monomorphiza...

Re:“Modern” C++ Lamentations by jules on Saturday December 29, 2018 @05:40AM (#18783019)
The compiler could do that automatically. Suppose you're operating on the control flow graph and you are to specialise a basic block in some type environment. You can cache the result so that the next time the same basic block is specialised in the same type environment you look up the result in the cache and create a call to that existing basic block.

  pub fn big_function<T: Into<i32>>(x: T) {
      let y: i32 = x.into();
      ... code that uses y but not x ....
  }
In the first line of the function you have the environment {T: Into<i32>, x: T}. After the let you have the environment {T: Into<i32>, x: T, y: i32}. If you keyed the cache on the full type environment you wouldn't solve the issue because the code that only uses y would still get specialised to the {T: Into<i32>, x: T} too. However, you could detect that that code doesn't actually use T and x, so that you can specialise it to the type environment {y: i32} only.

That detection can happen as a side effect of specialising that code to some particular {T: Into<i32>, x: T, y: i32} for the first time. As you specialise that code you record which parts of the type environment actually got used, and you use only those parts as a key in the cache. The type environment object itself could take care of recording what the compiler looked up in it. Another advantage of doing it this way, rather than analysing the code ahead of time, is that it can handle cases where a particular type variable does or doesn't get used depending on what type some other type variable is instantiated to. You could also use the same system to avoid duplicating code that only relies on particular aspects of a type. For instance, a function that permutes the values in a &mut[T] might only care about the size of T and not about the precise type T, so that all its specialisations to T of 4 byte size can call into the same code.

Another thing you'd probably want to do is integrate a basic form of constant propagation & dead code elimination during monomorphisation, so that you don't spend a lot of time monomorphising code that ends up dead for particular type instantiations.

Re:“Modern” C++ Lamentations by steveklabnik on Saturday December 29, 2018 @08:39AM (#18783498)
> The compiler could do that automatically

Yes, that's what I'm saying.

> Another thing you'd probably want to do

This is a very interesting idea!

Re:“Modern” C++ Lamentations by strmpnk on Saturday December 29, 2018 @12:52AM (#18782140)
The translation units in C++ tend to pay this cost a number of times over because of the way header files are processed. With modules, this theoretically could start getting closer to Rust, but for large projects, C++ templates can still be orders of magnitude worse in terms of instantiation cost.

This is partly why there are hacks like unity builds (not related to the engine, where all source is bundled into a single translation unit). These have plenty of drawbacks too so it's not a clear win.

Adding to all of this, there are fancier mechanisms for template meta-programming like SFINAE rules + computed template values. Sure, it's "turing complete" but this is why we see such clever libraries with huge explosions in code generation size. I'm far from an expert in modern C++ features but it's clear that there is an entire interpreted programming language of templates bolted on the to the rest of C++. It reminds me of this post on a similar take on Haskell type level programming: https://aphyr.com/posts/342-typing-the-technical-interview (or similar feats by Oleg Kiselyov).

Re:“Modern” C++ Lamentations by vmarsy on Friday December 28, 2018 @05:55PM (#18780154)
Thanks, that's an interesting read. indeed a developer can use that trick "in the case of conversion traits".

Monomorphization seems to be the source of 2 major problems: compile time, and binary size.

An optimization that could reduce the compile time by caching the generated code (at least when compiling over-and-over the same code base. i.e. "Incremental compilation") - and it seems that Rust already is doing something with it [1]. I wonder if something specific is done for template instantiations there.

Optimizations aimed at reducing binary size seems much more tricky, if not impossible, except as you pointed out in the limited cases described above. In the regular cases, templates are kind of working as intended: the developer has to think if he/she would have written the same amount of code N times if templates were non existent.

[1] https://blog.rust-lang.org/2016/09/08/incremental.html

Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @04:15PM (#18779472)
C does have a kind of lightweight generics since C11.
Re:“Modern” C++ Lamentations by fanf2 on Friday December 28, 2018 @05:52PM (#18780140)
Sadly C’s `_Generic` typecase mechanism does not do SFINAE: all the branches have to typecheck OK, regardless of which one is selected. This is OK for <tgmath.h> where the cases are different sizes of float, where there are few opportunities to get different failures in the different cases, but it makes _Generic hard to use for more template-like code.
Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @06:34PM (#18780371)
Given how hard SFINAE is to understand for typical developers, I consider it a good thing, actually.
Re:“Modern” C++ Lamentations by steveklabnik on Friday December 28, 2018 @05:09PM (#18779866)
Sure, but I’m not aware of them being used in any significant capacity, so I don’t think it’s particilary pertinent to this discussion.
Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @05:23PM (#18779960)
Ah, in that regard you are right, I guess.
Re:“Modern” C++ Lamentations by JulianMorrison on Friday December 28, 2018 @03:08PM (#18779083)
My feeling is that at least in C++ and Haskell, what's going on is that a barebones language core is being extended with a teetering tower of mutually dependent libraries building ever deeper abstractions. Templates upon templates, or monads upon monads.

Whereas in Go, say, stuff like ranges and maps is just built in, no more abstraction than is necessary to do a generalist job with a few specialised common cases. Even the standard library is largely one-level, direct code, and only abstract at the interfaces.

So simply and literally, C++ has to compile more lines of code to do the thing.

Re:“Modern” C++ Lamentations by gumby on Friday December 28, 2018 @03:15PM (#18779122)
This was of course one of the key differentiators of C; one of my favorite lines in the original K&R book was "what? I have to call a function to do I/O?"

C was unusual that so much of it was in its libraries rather than being built in. Programming language design in those days didn't have the clean differentiation we have today.. or perhaps did: it's fascinating to see the arc bend back.

Re:“Modern” C++ Lamentations by JulianMorrison on Friday December 28, 2018 @03:35PM (#18779217)
Being in libraries or in the language isn't so much the thing, because really the language is just calling into a hidden library. It's more being directly written, versus being composed of Legos that are themselves composed of Legos... that ends up drawing in a hundred thousand lines of ultra generalist code and then pre-specializing it.
Re:“Modern” C++ Lamentations by int_19h on Friday December 28, 2018 @05:18PM (#18779925)
It predates C tho. In Simula-67, not only I/O was in functions, it was in methods (on file objects). In Pascal, it was also all functions, also some of those were magic (e.g. overloaded on types, in a way user-defined functions couldn't be) - but it still described them as functions.
Re:“Modern” C++ Lamentations by gumby on Friday December 28, 2018 @05:36PM (#18780038)
I said unusual not unique, but perhaps I should have been clearer.

Pascal and C were definitely influenced by Simula, a language ahead of its time.

When K&R wrote that line I suspect they were thinking more of PL/1 which was the Multics implementation language. Though it has OPEN/CLOSE etc they were keywords not external labels.

I think it’s pretty likely K had heard of Pascal at the time.

More interestingly BCPL’s i/o was via library rather than innate. And c descends directly from BCPL (->b->c) rather than from PL/1; simula-67 and BCPL were developed contemporaneously in Europe.

Again, apologies for my prior brevity.

Re:“Modern” C++ Lamentations by zmj on Friday December 28, 2018 @02:50PM (#18778965)
Fast compilation was an explicit design goal for Go: https://talks.golang.org/2012/splash.article#TOC_4.
Re:“Modern” C++ Lamentations by erik_seaberg on Friday December 28, 2018 @02:29PM (#18778854)
It must be different ways people work. I can't imagine caring that my integration test suite might get 0.05 minutes slower.

Edit: especially if that 3 s pays for generating code that nobody has to write correctly or ever look at.

Re:“Modern” C++ Lamentations by kzrdude on Friday December 28, 2018 @02:14PM (#18778767)
Isn't it more about what the typical program looks like? The generic languages like Rust and C++ generate a ton of functions, wrapper types, and indirections that need to be seen through and mostly removed by the compiler.

In C++, when compiling:

   for (; *it; ++it) { }
it may look simple but deref is a function you insert (deref operator), `++it` is a function and so it continues on, with new function to generate each time it's a different iterator or even the same iterator with different template parameters.
Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @04:18PM (#18779494)
It also does not apply to .NET Native, Delphi, Ada, Eiffel for example.

On Haskell's case it depends on which compiler backend you are actually using.

So yes, it is a matter of effort spent in the code compilation, specially if the language does support modules.

Re:“Modern” C++ Lamentations by jackewiehose on Friday December 28, 2018 @01:05PM (#18778333)
And that is a really old problem. I remember trying boost::phoenix about 10-15 years ago but it was completely unusable because even the hello-world-example took like 10 seconds. Thats incompatible to my C++-workflow.

Today I'm trying to port some big old Embarcadero (Borland) C++ projects to their new clang-compiler but the compile times are so terrible that I'm not sure this will be usable at all (and these projects are mostly C++98).

Re:“Modern” C++ Lamentations by badsectoracula on Friday December 28, 2018 @01:17PM (#18778413)
Well, it doesn't help that Borland focused on compiler performance (i have Borland C++ 5.0 and i use it for a lot of my C coding since i write in C89+a few extensions that are supported anyway, because it takes around a second for a full rebuild for my code and is practically instant for a partial build - and that is for a singlethreaded compiler, for comparison the same code takes 4 seconds on a parallel build in gcc with make -j8). I don't know of any other (non-toy) compiler that focused on that. 15-16 years ago i used the free BC5.5 command line tools exclusively because on the crappy computer i had at the time (Pentium MMX at 200MHz with 32MB of RAM) it was the only that was fast enough to work with.

I've also played a lot with Borland C++ Builder and the compile times for C++ (pre-C++98) are comparable (that is, practically instant).

Re:“Modern” C++ Lamentations by 21 on Friday December 28, 2018 @01:21PM (#18778442)
> In which world is it okay to compile a trivial 5-line example three times slower than a full database engine

Well, as explained in the article, those 5 lines generate hundred thousands of lines of code behind the scene.

And you don't use C++ for fun, you use it because you have a serious performance problem. And in that case you'll wait the compile times, because there is no alternative.

Let's not even go into link time code generation or profile guided optimizations, which increase compilation times by another order of magnitude.

Re:“Modern” C++ Lamentations by zozbot123 on Friday December 28, 2018 @02:08PM (#18778730)
> those 5 lines generate hundred thousands of lines of code behind the scene.

That's part of the problem; most of the time, the "thousands of lines of code" that are created from type-generic code have a lot of useless duplication, and the compiler has trouble coalescing the duplicated and redundant code (I don't even think a serious attempt is made, AIUI). There's a lot of scope for improvement.

Re:“Modern” C++ Lamentations by adrianN on Friday December 28, 2018 @02:23PM (#18778824)
There is an alternative: writing simple C++ instead of Modern C++, or even using plain C.
Re:“Modern” C++ Lamentations by Koshkin on Friday December 28, 2018 @05:08PM (#18779850)
Then you increase the time you need to spend writing your program. You will also most likely end up cutting some corners, and the result will be of questionable quality in one way or another.
Re:“Modern” C++ Lamentations by thezilch on Friday December 28, 2018 @08:15PM (#18780982)
Holding in my brain and using all these "modern" features increases the time I need to think about code, data, and algorithms, and that's usually where most coding spends my time -- thinking.

And "modern" compile times... increasing the time between results and further thinking and writing. Don't forget that; the article doesn't.

And "modern" debugging... well, good luck.

Re:“Modern” C++ Lamentations by Koshkin on Friday December 28, 2018 @08:58PM (#18781222)
Well, people have been known to hold in their brains information pertinent to their trade. Professional training helps, too. I can only guess the extent of what a mathematician, a physicist or a medical doctor must remember to be successful in what they do.
Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @03:35AM (#18782664)
Musicians are able to hold complete compositions on their heads, some of them several minutes long.

It is all a matter of focus and pratice.

Re:“Modern” C++ Lamentations by kgabis on Saturday December 29, 2018 @12:31PM (#18784658)
Code is not music. When thinking about code you must keep track of possible branches executed code might take and properties of the physical machine it runs on. C++'s complexity can hide code's underlying logic and make some types of bugs more common.
Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @01:20PM (#18784900)
As someone that learned music and several instruments before getting into computing, and having spent several evenings with musician friends, I beg to differ.

Writing a composition score for an orchestra falls under similar conditions, how each instrument sounds, how they sound together, when each comes and goes into play, and so forth.

Most complaints about C++'s complexity can be equally applied to languages that look deceivably simple like Python.

Complexity is like thermodynamics, it gets pushed somewhere, if it isn't on the code, it gets shoved either into boilerplate, or architecture.

Re:“Modern” C++ Lamentations by thezilch on Saturday December 29, 2018 @03:44PM (#18785579)
If we can compare C++'s complexity to Python's, then C++ has lost its way. You're saying the same thing as the article and my comment, that C++ is trying to hide complexities, and we're arguing that doing so is instead adding more complexities.

Sure, Python makes it easy to listen on a socket, parse HTTP, and send HTML down -- hiding a lot of complexity. But it's made it impossible to do so very efficiently and scale up. Try and dive into Python's stack for that (Re: 'hold in your brain all the "modern" features'), and you'll get lost in a myriad of CPython (or whatever flavor you choose) generics and indirection that you can't optimize. Startup times matter, because you are all about hiding complexities and went "serverless" and constantly eat cold starts (Re: '"modern" compile times').

I think it's apt to compare "modern" C++ as moving towards something like Python. Not great for a lot of applications of C++ (Re: games, in the article and my focus) or its perceived goals as a better C. That's the point. Many of the C++ additions are being slagged for making a worse C. It's looking nothing like C any longer. It's a giant ball of complexity with dozens of ways of doing the same thing and hoping you learned them all.

This is why I think languages like Rust (or even Go) get a lot of attention. They have a good interop story with C, like C++ has. And if we're going to learn a bunch of non-C looking language grammar, C++ is doing a worse job.

Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @05:32PM (#18786097)
My point about Python is that it is always presented as begginer friendly language, yet is it quite complex for anyone that whats to fully master it.

The language + standard library + C API references are around 2392 pages, not counting the other minor documentation like the 500 PEPs, release notes and differences across each Python release, even minor ones.

Then there is the whole set of meta-classes, decorators, mixins, generators, operator overloading, multiple inheritance, abstract classes, fp like programming and much more.

The big difference to C++, is that the community doesn't care about performance, leaving the PyPy guys a Quixotic battle regarding adoption, which isn't the case with C++ compilers.

Even C isn't as simple as many think, with its 200+ documentated cases of UB, and the days that C mapped 1:1 to PDP 11 Assembly are long gone.

How C code looks like, and what gets generated via auto-vectorization, GPGPU code, SIMD intrisics are very much two worlds appart.

Re:“Modern” C++ Lamentations by thezilch on Saturday December 29, 2018 @08:17PM (#18786738)
You're absolutely right that Python has also become more and more complex and often not for the best.

As for Python performance, on the contrary, I think there was a large portion of the Python community that did care during my years with it. I think 3.x adoption was hurt a lot by being slower than 2.7.x. I think a lot of the community jumped ship to Golang or similar, for both performance and complexity reasons.

I would absolutely love for C++ to tackle C UB or make incompatible insecure C. Instead, we get stuff like Ranges, time and again. I'm struggling to understand what complexities you are finding it covers that are worth supporting forever, committing gray matter, committing productivity loss, committing debug travesties, &c. Say I'm a musician that can hold complete compositions in my head; why should I commit this feature and its baggage to memory?

Re:“Modern” C++ Lamentations by pjmlp on Sunday December 30, 2018 @04:40AM (#18788320)
> Say I'm a musician that can hold complete compositions in my head; why should I commit this feature and its baggage to memory?

Because C++ is the sane alternative to C on OS SDKs, HPC, GPGPU programming, regarding portable code.

Now, ideally as memory safe systems advocate, I would like to see more of Swift, .NET Native, D, Go, Rust, Java (AOT), OCaml, ...

However, when using languages not endorsed by vendors, it always means inferior IDE/debugging experience, lacking IDE support, manually writting FFI integration code, tracking down which layer is responsible for certain bugs,..., so switching to something that looks easier turns out to become harder in the long run as the whole stack experience suffers.

There are already signs of OS vendors finally improving a bit the situation, with Apple continuously pushing for Swift, Google restricting what is at all possible to do with NDK, Windows teams focusing on .NET Native in spite of C++/WinRT (nee C++/CX), Rust adoption by all big names.

However we are still at least a decade away of any of those languages enjoying a similar industry position in platform SDKs as C++ enjoys nowadays, after 30 years fighting against C.

So I rather keep that baggage in memory, while doing my best to use modern C++, alongside the other more type safe languages, also part of the respective platform SDKs, than additing additional attrition to my production code toolbox.

I imagine my opinion is not unique.

Re:“Modern” C++ Lamentations by kgabis on Saturday December 29, 2018 @04:16PM (#18785728)
As someone who also learned music and played several instruments (violin, piano) before getting into computing I still don't get what's the point of comparing musical memory to being able to recall programming language rules. Programming is largely about managing complexity and our mammal brains are not very good at keeping track of all the exceptions and special cases a language like C++ is full of (as opposed to remembering music). Just to be clear: Yes, writing music, especially for an orchestra, IS hard and complex.
Re:“Modern” C++ Lamentations by gok on Friday December 28, 2018 @02:56PM (#18779015)
By simple you mean without the STL?
Re:“Modern” C++ Lamentations by z3phyr on Friday December 28, 2018 @11:18PM (#18781798)
C with polymorphism
Re:“Modern” C++ Lamentations by gok on Saturday December 29, 2018 @02:11AM (#18782422)
Including virtual/dynamic polymorphism?
Re:“Modern” C++ Lamentations by modeless on Friday December 28, 2018 @02:22PM (#18778818)
If you really have a serious performance problem, the answer these days is more likely to be a GPU, DSP, FPGA, or even an ASIC. The era of C++ on CPUs being the right solution for most high performance computation problems is coming to a close now that Moore's Law is ending.
Re:“Modern” C++ Lamentations by muro on Friday December 28, 2018 @02:41PM (#18778917)
If you deploy the code on a large number of machines, especially out of your control, most of those don't apply. There is a large scale of problems that require/benefit from optimised non-GPU code: - OS and related tools - applications (e.g. image processing, spreadsheets, engineering applications) - browsers - games - compilers - low level libraries - databases

Yyou are probably using many of those and would not enjoy them being slower.

Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @04:22PM (#18779521)
Even though I do like C++, I kind of agree.

As Wirth languages fanboy, I belive that if Java 1.0 had AOT compilation from day one, instead of leaving it to commercial third parties, and proper value types, the amount of C and C++'s adoption would have looked much different.

Re:“Modern” C++ Lamentations by Koshkin on Friday December 28, 2018 @05:13PM (#18779885)
I wonder what Wirth would have to say about Java...
Re:“Modern” C++ Lamentations by pjmlp on Friday December 28, 2018 @05:22PM (#18779954)
As you might imagine, not kind words.

"Modern languages like Java and C# may well be superior to old ones like Fortran, PL/I, and C, but they are far from perfect, and they could be much better. Their manuals of several hundred pages are an unmistakable symptom of their inadequacy. Engineers in industry, however, are rarely free from constraints. They supposedly they must be compatible with the rest of the world, and to deviate from established standards might be fatal."

https://www.inf.ethz.ch/personal/wirth/Miscellaneous/IEEE-An...

"In 1995 Sun Microsystems presented its language Java , fully 6 years after Oberon. It incorporated much of the "philosophy" of Oberon, but, alas, chose the style and syntax of C. Around 2000 Microsoft released its language C# as a strong competitor of Java, and Google followed in 2007 with its language Go, even more strongly following (the 18 years old) Oberon. The crux with these languages, which all became wide-spread due to strong industrial support, is their size and complexity. The ambition to provide everything to everybody prevailed and let them grow into complex bodies difficult to master."

https://www.inf.ethz.ch/personal/wirth/Miscellaneous/Compute...

Re:“Modern” C++ Lamentations by makapuf on Saturday December 29, 2018 @01:33AM (#18782283)
Using complexity as an argument against Go is not really accurate in my point of view.
Re:“Modern” C++ Lamentations by pjmlp on Saturday December 29, 2018 @03:06AM (#18782580)
It is, because after Modula-2, Wirth's goals have been to produce the minimalist, type safe, systems programming language.

Oberon-2, Concurrent Pascal, Active Oberon and Zonnon variants were designed by students or together with ETHZ fellow researchers.

Oberon is smaller than Modula-2, and Oberon-07 lost features on each language revision.

So from our point of view Go isn't complex.

From my point of view Go still lacks several features, which Go 2.0 will kind of address.

However, from Wirth's point of view, which after being retired was still trying to design such minimal language, Go is indeed complex.

You can see this by reading the language reports.

https://www.inf.ethz.ch/personal/wirth/Oberon/index.html

Re:“Modern” C++ Lamentations by aldanor on Friday January 04, 2019 @08:23AM (#18823781)
This shouldn't have been downvoted.
Re:“Modern” C++ Lamentations by Gibbon1 on Friday December 28, 2018 @03:34PM (#18779213)
I totally disagree, I think that era has been over for the last 20 years.

I keep coming back to a talk by Daniel J. Bernstein, that the assumptions computer science teaches about performance are wrong. His claim is for real programs most code is ice cold and a tiny percentage is hot. And that's getting worse not better as time goes on.

What important is; correctness, latency, compile time. Not raw speed.

Re:“Modern” C++ Lamentations by adrianN on Friday December 28, 2018 @03:54PM (#18779336)
In my experience that claim is very true before you fire up your profiler. But once you've optimized your program for a bit the profile gets a lot flatter.
Re:“Modern” C++ Lamentations by Gibbon1 on Saturday December 29, 2018 @10:44PM (#18787251)
I think if your programs profile is flat it means none of your code is actually in the hot path. It's buried behind library functions and OS calls.