Giving up on Julia (2016)
zverovich.net
zverovich.net
I don't think it makes any sense to speak of "__x slower" for hello-world. Clearly, this is just a benchmark of startup time, so you only pay it once per program. It should be reported as "__ms slower".
Julia startup (according to this post) takes 371ms. That's 357ms slower than Python, and 369ms slower than C. Faster is always better, but this doesn't seem so bad to me.
For comparison, on my old workstation here, starting a Swift repl takes 2724ms, and starting a Clojure repl takes 4792ms.
But people who like the language will invariably use beyond its core competency.
Hence it is important to ensure that julia is "kinda mediocre" for CLI scripting (big step up from "absolutely terrible"). Personally, my familiarity with julia and its features outweighs the fact that python/perl/bash would be the better tool for many CLI scripts.
My own bioinformatics work involves parsing massive amounts of text data, and Julia is excellent for this -- it is very fast, yet high-level and easy to write. However, bash pipelines are also a huge part of bioinformatics, and Julia scripts are not very good for this due to the long startup time, which is a shame.
I think it’s still early in the languages development to say that. There isn’t any fundamental reasons Julia couldn’t be tuned to be better at CLI scripting. Currently it’s what, 400ms to startup, which isn’t too terrible but could be made faster. I could see using the Julia debugger as an interpreter for CLI scripts. Or if you run a script a lot it’s possible to have Julia compile an executable. Personally I use it in mainly via notebooks or a repl.
> time julia -e "exit()"
real 0m0.164s
user 0m0.106s
sys 0m0.047s
This is on a relatively old laptop: Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz
according to my lscpuFor an example of what I mean by the latter, python seems to be pretty fast initially, but then seems to take a huge hit from just trying to get numpy loaded.
$ time python -c '0'
real0m0.024s
user0m0.016s
sys0m0.008s
$ time python -c 'import numpy'
real0m0.165s
user0m1.508s
sys0m2.312s
$ time ./julia -e 0
real0m0.215s
user0m0.240s
sys0m0.144s $ time python -c '0'
python -c '0' 0,03s user 0,01s system 7% cpu 0,467 total
$ time python -c '0'
python -c '0' 0,03s user 0,00s system 98% cpu 0,030 total
$ time python -c 'import numpy'
python -c 'import numpy' 0,17s user 0,05s system 9% cpu 2,401 total
$ time python -c 'import numpy'
python -c 'import numpy' 0,11s user 0,01s system 99% cpu 0,118 total
$ time julia -e 0
julia -e 0 0,25s user 0,27s system 17% cpu 2,868 total
$ time julia -e 0
julia -e 0 0,09s user 0,05s system 92% cpu 0,155 total
The impact of actually calling something from numpy is also negligible in Python but not in Julia: $ time python -c 'import numpy; numpy.random.rand(10,10)'
python -c 'import numpy; numpy.random.rand(10,10)' 0,10s user 0,01s system 99% cpu 0,116 total
$ time julia -e 'rand(10,10)'
julia -e 'rand(10,10)' 0,35s user 0,23s system 209% cpu 0,277 total
$ time julia -e 'rand(10,10)'
julia -e 'rand(10,10)' 0,36s user 0,22s system 209% cpu 0,278 totalConsider https://github.com/JuliaLang/julia/issues/30044
You can manually enable buffering of the pipe endpoints. Otherwise julia will be super-duper-slow when part of a pipe.
(OK, the pipe buffering rules still annoy me)
Similar with FFI: Julia has awesome support for calling out to other languages; support for getting called by other languages is suboptimal.
That would be dependent on hardware, while the relation will be constant.
As a simple example, if two computers are comparable in speed but one has a bigger cpu cache or faster ram, they might run programs with low memory footprint at the same speed, but one will be much faster when running a program that uses a lot of memory.
> If you ignore startup time, Julia might have good performance for simple array/matrix operations and loops, but we already know how to make them fast in Python and other languages.
> And it’s not just scripts, Julia’s REPL which should ideally be optimized for responsiveness takes long to start and has noticeable JIT (?) lags. What’s even more worrying is that there doesn’t seem to be much progress there. The REPL was a pain to use a year ago and it still is.
> In addition to that, Julia programs have excessive memory consumption. The above hello world example in Julia uses 18x more memory than Python and 92x more memory than the C version.
Again, I'm left wondering if this is proportional, or simply an X megabyte overhead of the runtime. Maybe it's even shared among all running programs, as some runtimes are. Or it looks like maybe stdio could be just particularly bad in Julia, and in practice I've never written a program for any environment where that was my performance bottleneck.
Performance is not easy to measure, and not easy to report. A single number makes a good headline but it's really not enough information.
Which is why the benchmarks game measures at more than one workload —
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Yes, by not executing them in Python, the universal trick to make anything fast in Python.
Julia's whole shtick is avoiding having to drop down into C.
I find D's better-C dialect to be a definite improvement across the board, but there is a lot of institutional inertia behind C.
My peers and I use Julia to run numerical heavy code where the large majority of the time is spent inverting a large matrix to solve the equation Ax = b for x. It's a lot more complicated than this, but essentially it can be boiled down to this main equation. When my code takes hours, pushing onto days, to run, why should I care about 300 ms of startup time at all?
I stopped reading the article because their first point (the hello world benchmark) is entirely meaningless and is just noise in the wind. Their second point is a matter of personal opinion. After these two I didn't bother reading the rest.
Please share your comparison of every programming language implementation.
Moreover, even in some server-side applications it's super neat to have the luxury to spawn a new process to service certain requests, not having to worry about memory leaks. It's a perfect "API" which allows multiple languages to interact together.
It always bothered me when people dismiss the start-up time by adding "just" in front of it. We're not talking about web frameworks, these are _general purpose_ programming languages, and horrendous start-up time automatically disqualifies them from being general purpose and places them into a niche category, in my humble opinion.
So, I implemented exactly the solution you describe here. I made my interpreter run as a daemon and listen for requests on a Unix domain socket (with a custom binary protocol). I then wrote a client in C, which opened that Unix domain socket and sent it a script to run. The C program also redirected stdin/stdout/stderr to/from the interpreter through the Unix domain socket, if connected to a tty it could switch to/from raw mode, it notified the server if certain signals occurred, etc. Using the interpreter this way, startup time was a lot faster. This approach can be applied to any language which supports runtime evaluation of code.
The issue with missing-normal-capability processes is more difficult to address. One possibility, at least on Linux, would be to get the pid from SCM_CREDENTIALS message, and then read /proc/$PID/status to check capability bits. It could default to denying access to processes with less capabilities than it itself has.
(SCM_SECURITY can be used to pass the SELinux security label from client to server, which could also be used as a security measure; maybe the server could refuse access to processes running with a different label, or have a whitelist of allowed labels; if SELinux is being used to sandbox a process, that would prevent it from accessing the background interpreter unless that was explicitly allowed by whitelisting.)
Check the REPL experience from Lisp Machines and Xerox PARC Lisp/Mesa/Smalltalk workstations.
Think of Swift Playgrounds or Jupiter notebooks, done in late 70's hardware.
Or that different languages require different approaches, and you can't translate 1:1 between technologies. My Mac starts up 27x slower than my C=64, but that doesn't make it useless for any task that requires turning it on.
> We're not talking about web frameworks, these are _general purpose_ programming languages
Are we? I've never written a line of Julia in my life but the impression that I get is that this isn't intended to be a general-purpose language:
> Of course, one might argue that Julia is not intended to be a general-purpose programming language, but a language for numerical computing.
> As has been pointed out elsewhere “Base APIs outside of the niche Julia targets often don’t make sense” and the general-purpose APIs are somewhat limited.
The Julia webpage has 6 tabs listing features, and 5 of them are about numerics. The 6th says "General Purpose", but it's mostly about FFI.
Even if we don't use technicalities, Julia is a very powerful language that allows people to extend it for purposes it was not built for. If it didn't support JSON, you could write a JSON type as integrated and fast as what the stdlib offers, it's metaprogramming/multiple dispatch paradigm allows for easily creating frameworks for many purposes and while numerical processing gets special attention the language will still outperform in terms of speed most dynamic languages in any domain.
And I do think short scripts are within Julia's main targets and are merely victims of the fact that the language is still too young and the battles the devs chose to fight within that limited time (and either AoT options or an interpreter that runs code while it's compiling could solve it really well for example, but both would require a lot of time and work which could be used for other features).
People will try all sorts of weird language experiments, so it's no surprise those libraries exist. But do you really expect a significant number of web developers to shift over to C, just because it's technically possible?
https://www.micrium.com/rtos/tcpip/
Quoting the relevant quote "you wouldn't use C to write your simple website", except that is exacly what EE does when on device memory is measured in KB.
C++ would be safer, but the C89 culture reigns in such domains.
Micropython is not really python (which by definition is defined by PEP and CPython implementation), it's a language largely similar to python 3 since you can't just pick a python program or library and run on it at all times, but it's not really a relevant discussion (and it's nice to have multiple variants of a language you like that are good for multiple purposes, which solves the bloat problem as long as you use only one of them at a time).
Regardless, I hope Julia gets to the point that you can target as many places as some of those languages even if it's not nearly the best in each domain (like WASM, embedded, OS stuff, shared libraries).
I get your point, though.
If you want to build CLIs without the JIT overhead, you can compile your Julia code: https://github.com/JuliaLang/PackageCompiler.jl
It is still crazy big, because it still has to include the LLVM compiler in it.
This is not true for Julia, you can simply precompile the code: https://medium.com/@sdanisch/compiling-julia-binaries-ddd6d4...
Julia's default model is that script functions are only JIT compiled when run (just like the JVM, etc.), but you can just as easily force the compile and stick it in an image.
Have you actually tried the instructions in there? I did, to get a better time for julia in the n-body programming languages shootout https://benchmarksgame-team.pages.debian.net/benchmarksgame/... (I am the current leader among julia implementations). Suffice it to say, it did not work. I mean i'm not a brilliant programmer or anything, but I would hardly say it's "just as easily".
I think the only non-stdlib package I used was StaticArrays, but I was able to use the happy path described in the PackageCompiler docs and got it working in an hour or so max. This was probably in March or April, so relatively recent.
I didn't have any non-stdlib packages at all!!
I'll give it another shot.
The REPL is a tad slow but compiled Swift binaries have virtually no startup time overhead.
Clojure can be targeted for graal afaik. Not sure how well it works though.
I’ve become disenchanted with clojure over the last couple years, so I haven’t tried anything recently.
I've been trying to get into it last 6 months :p. Now I am Wondering why you say this.
`date 1>&2 | sleep 1 | date 1>&2 | sleep 1 | date 1>&2`
you'll actually see the three date commands output immediately so the three julia processes would actually launch in parallel if they were in a pipe
its a julia issue that the devs refuse to acknowledge or even test
The Swift repl is essentially a debugger running a compile-run cycle on each entered expression. Some statically-compiled languages have slow compilers but extremely fast runtime execution (Rust, and to a lesser extent C++, come to mind).
We have working code to code automatic differentiation:
https://github.com/FluxML/Zygote.jl
Finally, the core team is paying attention to the problems and addressing them. All my top complaints are already mentioned in the laundry list:
Julia language development seems to be guided towards avoiding making damaging mistakes on the long run (for example focusing early on having a stable programmable multi-stage compilation, very efficient union-types and state of the art multithreading so the library ecosystem can grow with the correct assumptions). But the "time to first plot" is something that can be solved (regardless of it being hard or easy) at any time "with no consequences", since libraries written with the expectation of a slow startup will work just as well when that problem is solved. Though the compiler team did acknowledge the issue and are prioritizing it post 1.3.
I do wonder if focusing on doing the very simple things well first (like python does right now), would be a better strategy, or it would just make people ignore the language because the simple things are already covered everywhere and not interesting enough for bringing people (compared to the amazing stuff Julia can do with supercomputers/clusters and state of the art stuff like Zygote).
This is just the difficulty of open source. I am a mathematician by trade, so I work on DifferentialEquations.jl, Zygote.jl, new forward-mode AD, and showcase this stuff in neural differential equations as part of my work. While it would definitely be nice if someone focused on startup speeds, it's not going to be the DiffEq/Zygote people, because it's not the stuff that I/we know. Julia has tons of great scientists and mathematicians, so the libraries in that area are pretty fantastic already, but we do need to find some people who know how to write apps and do devops. I plan to actually find and hire some devops people to help out Julia here. Julia has shown from its libraries that it's worth supporting, so now we should tie a bow around it for less hardcore folks.
This is just blatantly false.
I love Julia for statistical analysis.
I never needed speed when printing out stuff.
REPL should be much faster (especially importing libraries), and I'm not a fan of 1 based indexing, but everything else is awesome if you need great performance.
Also I'm missing a great Julia native graphing library with zooming support (Matlab's is far better).
Production binaries are very hard to make, but for statistical research I don't know any better software.
Also for unit testing asserts are good enough for me.
> REPL should be much faster (especially importing libraries), and I'm not a fan of 1 based indexing, but everything else is awesome if you need great performance.
Then don't you want fast printing / string ops? REPLs heavily rely on that.
That's not how (barely) anyone actually works with Julia when they do data-analysis though.
R?
My favourite examples of Julia's great type system are its automatic differentation libraries that take a native function and wouldn't be possible with R.
Complaining about start up times for a JIT implies your numerical work isn’t that heavy (and why not compare it to C compilation times in that case).
That sprintf comparison is ridiculous as it doesn’t show how much assembly follows that jump, it’s just argument packing.
And calling C can indeed segfault.
Performance: It's been mentioned by others that JIT and Julia is a thing. An important point that many here seem to be unaware of is that you can compile your Julia code [0], and then end up with a fast Hello World, if that kind of thing floats your boat.
Language style: This is more or less a subjective thing, right? However, I've found that optimising for JIT forces me into writing short and pure functions. I.e., optimising my Julia code for speed also forces me to write clean code. This is a really nice byproduct of the language design.
Libraries: The complaints seem somewhat thin: there is no mention of the type of unit tests that the author is missing, just a complaint that the library is less featured than some in C++ or Java. Is comparing a pre-1.0 language's unit testing libraries to those of C++ and Java a fair thing anyway? Finding that the generated instructions of a print statement are too long for your liking also does not seem to me to be a fair criticism of the language libraries.
Development: Complaining about the codebase being a mishmash seems unfair to me as well. I find myself browsing source code in Julia much more than other languages. With Julia I can just dive in and generally find that what's relevant to me underneath is also Julia.
I guess negativity gets clicks.
There's a macro @simd which lets you write a for loop and it will convert it to simd.
From the docs: "In many cases, Julia is able to automatically vectorize inner for loops without the use of `@simd`. Using `@simd` gives the compiler a little extra leeway to make it possible in more situations."
The benefit is that it's more familiar to scientists who have experience with Mathematica, MATLAB, R, or Fortran. It's fair to compare the pros and cons of this choice, but you have to at least mention the pros.
And yes, perhaps one based indexing introduces a class of bugs when you need to call into c. But zero based indexing has the same problem if you need to call into fortran, and calling fortran is really common for numerical code.
Most of the classic linear algebra algorithms seem to be described using 1-based indexing and the last time I needed to use one of these algorithms, I stubbornly tried to translate everything into zero-based indexing which was more difficult than you'd imagine and it was difficult to have confidence that I had correctly captured the algorithm.
I switched to using a 1-based matrix implementation and everything became trivial. It's not that hard to switch between looping from 0 to n (exclusive) and looping from 1 to n (inclusive).
I suspect the main reason 1-based seems convenient for some things is because of convention. Note that 0 wasn't even really used in mathematics until hundreds of years after our system of counting years was created.
Since our year counting is 1-based, we end up with odd things like "2019" being the "19th year" of the "21st century" as opposed to "2018" being "year 18" of "century 20". I suspect it's also fairly unintuitive that the current century began in the year "2001" rather than "2000".
Wow that's the best argument in favor of 0-based counting I've ever heard :)
And since pointer arithmetic is based on offset, it wouldn't make sense for C to use anything other than 0-index. But mathematical languages aren't focusing on mapping the hardware in any way, but to map the mathematics which already uses 1-index for vector/matrix indexing. You can see the relation of languages in [1].
If you want to write generic code for arrays in Julia, you shouldn't use direct indexing anyway, but iterators [2] which allows you to use arrays with any offset you want according to your problem, and for stuff that is tricky to do with 1-indexing like circular buffer the base library already provides solutions (such as mod1()).
[1] https://en.wikipedia.org/wiki/Comparison_of_programming_lang...
This is again just begging the question. When you want to refer to the initial element as the "1st", it is due to the established convention of starting to count from 1. The point is that the reasonining for starting from 1 might only be that: conventional, not based on some inherent logic.
But then I agree that there is no inherent logic, math is invented and not discovered, and you could define it any way you want. If we all had 8 fingers we would probably use base 8 instead of 10 after all.
It just so happens that this edge case of 0 things doesn't occur when we actually need to count something. Starting from 1 is kinda like head is a partial function (bad!) in some functional programming languages. Practicality beats purity.
f = v0 + x
f = v1 + x
Those are the same equations right? Sure, but when I see v1 I'm not really sure what it is or could be, vs if I saw v0 I can assume it may be the initial velocity when I can look up.
Since my experiments are just some simple implementations of kmeans and bandits epsilon greedy algorithms take what I'm going to say with a grain of salt. Anyway:
I find Julia very interesting. I managed to make kmeans fast with type annotations. If I were to summarize I would say that Julia is a much better cython. I never managed for example to debug cython. Profiling also seems to work in Julia, another thing very hard to do in Python. On the other hand, as in cython, sometimes you don't know if some missing type annotation is slowing your program. It remains to be seen if the "verbosity" of type annotations is going to help or slow its adoption.
The lack of type annotations won't slow down your Julia program, since the compiler will infer them anyway (types are for multiple dispatch, documentation or to assert types, not speed). What will affect it is if the type can be inferred or not. For example, if you have a variable that is sometimes an int, sometimes a float, sometimes a string it will force the compiler to put the checks on runtime, dropping performance to CPython level (although the compiler optimizes small unions, such as Union{Int, Nothing} for a nullable Int). That's what the community calls type-stability, and the first step of profiling a function is usually using the macro @code_warntype to see what the compiler is inferring. See:
https://docs.julialang.org/en/latest/manual/performance-tips...
Personally, I do a lot of computational geometry in Julia and I really don't care so much about these kinds of small overheads since actual computation time is the dominant factor. I imagine if Julia was designed for scripting in Unix environments this would be a bigger deal, but I think most people in the Julia community care more about how to manage several gigabytes of data in RAM/cache and run some analysis quickly, e.g. composable multithreading in 1.3.
But the main point is that the critique is misguided in its generality. If the author cares about running many small scripts that each take a handful of milliseconds, then julia is just not the right tool for his job. No need to write overly general angry posts like "julia is slow"; instead write "julia has sluggish startup time". This is to some extent unavoidable, since julia has a quite heavy runtime (need to load llvm). For some workloads, bash / python / perl are more appropriate tools.
To give you an example, `$ time julia -e "print(5)"` gives me about 230 ms, compared to python 35 ms.
The language is designed for longer running programs that compute heavy stuff. And it performs very well at its intended use.
Fast startup, high throughput, high productivity: Choose two.
C/C++/Fortran take fast startup and high throughput, python takes fast startup and high productivity, and julia takes high productivity and high throughput.
Creating an array of three numbers is much faster; on my system (subtracting startup time) it’s less than 50ms, and that’s all because of compilation time. After running it once (so as to compile the random number generation and array construction routines) constructing a random array takes ~4ns.
Again, we’d like to see an issue opened in our github tracker to help figure out whats going wrong. Feel free to open one at https://github.com/JuliaLang/julia
I've been writing julia for almost a year. For this purpose, no other language comes even close.
The start will be slow, since the compiler will be aggressively optimizing and compiling everything it can (not unlike if you had just the source code of a C++ program and wanted to run for the first time), but over time pretty much everything will be already compiled to high performance code so the program, if written adequately, will run at similar speed to C, but it can still be modified at runtime like any dynamic language (which it can then compile as well).
Unfortunately, while the startup time has improved, I still find the JIT compiler overhead makes it unsuitable for most shorter scripts - the sort of thing where I would normally use python or R. Taking a few minutes to produce the first plot of the day while julia recompiles the plotting packages dependency tree is just a pain.
Edit: After a fresh install of 1.1, I found loading the Plotly package takes 4 seconds from a fresh repl, while the first plot with the Plotly.jl backend (plot(rand(5,5),linewidth=2,title="My Plot")) takes 14s, and subsequent plots take less than 1s on my computer. This is a marked improvement on 0.6, which is where my few minutes came from. Couldn't get PyPlot to work.
Granted, if you were plotting in a small script, I guess every run would take about 7 seconds to get the plotting functionality.
A Julia debugger was introduced recently [1] but its in a very early stage.
As far as Julia criticisms go, the Dan Luu post felt like it focused more on the right things (https://danluu.com/julialang/, circa late 2014). Of the two, that's the one I'd like to see a follow-up for.
For now, there is of course also packages available like https://github.com/JuliaIO/Formatting.jl.
[1] https://discourse.julialang.org/t/julia-v1-2-0-rc3-is-now-av...
[2] https://discourse.julialang.org/t/julia-v1-3-0-rc1-is-now-av...
So this reads a little bit like yet another review of a math DSL, written by and for people who don't need or like math DSLs.
Not surprisingly, it comes out negative.
What's Bad About Julia (https://www.youtube.com/watch?v=TPuJsgyu87U)
TL;DR: Julia is not that bad.
But if you really want to write something that's fast you won't write it in Python, Julia, or these days - C. You would probably use C++ (in a non-C-ish, non-OOPish way), and in some cases (think DBMSes) you'd craft your own LLVM IR and have it JITed.
Also I don’t like the begin/end block delimiters, but it’s not a huge deal. The Julia people keep repeating that curly brackets are too valuable, but I’m not at all convinced.
In addition, Julia should just give up on dynamic typing and make static typing mandatory. I understand why they allow it, but I still don’t agree.
julia> df = DataFrame(x = 1:10, y=2:11)
julia> df[1,:] DataFrameRow │ Row │ x │ y │ │ │ Int64 │ Int64 │ ├─────┼───────┼───────┤ │ 1 │ 1 │ 2 │
julia> m = rand(10, 2);
julia> m[3,:] 2-element Array{Float64,1}: 0.013457628869001814 0.2632480919750453
As for static typing/static analysis, that's something that can be built inside Julia (and several projects have done so). Personally, I would not want Julia to insist on static typing and much power comes from not overspecifying types.
C code generation only got where it is nowadays thanks to endless money spent in compiler optimization, taking advantage of UB beyond its original goal and compiler specific language extensions that probably will never be part of ISO C.
Nothing that other compilers cannot get if there is willingness and enough money to throw at improving them.
"Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue.... Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels? Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities."
-- Fran Allen interview, Excerpted from: Peter Seibel. Coders at Work: Reflections on the Craft of Programming
Could you consider switching to another quote? I've read that one at least half a dozen times. I promise I will not annoy people here by picking one from the millions of quotes out there that report that C (or similar) is a good abstraction level to develop efficient and maintainable software.
To put that quote in perspective anyway, the way I'm reading it isn't even that other (managed) languages can meaningfully rival C in its core strengths. It seems to be more about how interest in improving those managed languages faded (at that time) and the state of the art of compiling those languages regressed..
And regarding "endless money spent in C compiler optimization", neither is UB extremely interesting for optimization nor is optimization extremely interesting for already well-written programs. (I have only my own humble experience so can't really back this up. But question, when was the last time you got a 10x difference between -O0 and -O2?).
(I've disagreed with quite a few of your comments recently. Just wanted to let you know that the last thing I did was upvote some of your comments ;-])
I was already hitting on C during the USENET days, back on the glory days of C vs C++ on comp.lang.c, comp.lang.c++, and their moderated variants.
My opinion does not change to win karma points.