I wouldn't call Lombok "modern", more like "a terrifyingly hacky way to tackle limitations in the language despite the unwillingness to make the language friendlier" and a far cry from what source generators can do in C#
As a fan of Records, this is a punch to the gut.
The ecosystem is years and years away from using records. Almost every huge monolith decade+ project is still on Java 8, those who moved to something new still can't be liberal with them, because oh look, none of the serialize/deserialize libs can work with them because everything, to this day, abuses reflection for generating objects like a giant fucking hack it is.
Apology for the rant, but I migrated a big project to 21 early this year, am in the middle of migrating another 1M+ line codebase to 21, and the sorry state of records is such a sad thing to witness.
I give a decade before records are anything but 'a fancy feature'.
With that said - lombok is not needed at any form there either, use a c-tor with fields and make the public final. If you have too many fields in a class, it's likely a good idea to split it regardless.
In all cases dumb getter/setters are just public fields but taking more meta space (and larger byte code, the latter has some consideration when it comes to inlining)
Also, if I had 1M LOC and my serialization/communication libraries didn't support whatever I've picked - I'd patch the libraries to support it.
And I'm saying that even after writing the most of the first project (closing in on 100kLOC now) in 21, I still can't have records where the make the most sense (service boundaries) because libs and larger ecosystem don't support them.
> Also, if I had 1M LOC and my serialization/communication libraries didn't support whatever I've picked - I'd patch the libraries to support it.
1MLOC in java land is.. not unusual. And if you're talking about patching libs like jackson/jaxb/whatever, my good person, you truly underestimate how much actual work people have (where Java upgrade is a distant afterthought, I only did it because I wanted to scratch the itch and see how far I could push processes in my org), or how much impact that might have for a drive-by contribution. Updating such core ecosystem libs in java is no small feat. They are used absolutely everywhere, and even tiny changes require big testing. There is a reason you find apache libs in every single project, because they have matured over past couple of decades without such drastic rug-pull of a change.
Also I'd actively remove all apache commons as well. Even in Java8 most of the functionality is redundant.
With all that I meant it should not be really underestimation.
I am part of the dark matter, although self-initiated java upgrades already put me on the right side of bell-curve.
> Also I'd actively remove all apache commons as well. Even in Java8 most of the functionality is redundant.
I used to think that. Then I had to decompress zip files in memory and selectively process the children. Of course Java has the functionality covered in stdlib, but they require so much boilerplate, and commons-compress was such a pleasure that I was done in 10 minutes. The same goes for other apache libs too.
OTOH, I wholeheartedly agree about Lombok being unjustified curse.
But even, if you account for that, the records in Java do most of what Lombok used to do - make class externally immutable, add default `toString`, `equals` and `hashCode` implementations, allow read-only access to fields.
> what source generators can do in C#
Having had the displeasure of developing source generators in C# (in Rider), what they do is make code impossible to debug while working on it. On top of relying on an ancient version of netstandard.
I cannot emphasize enough how eldritch working on them is. While developing, whatever change you write isn't reflected when you inspect codegen code, and caching can keep old code beyond even post re-compilation unless you restart the build server, or something.
So whenever you try to debug your codegen libs, you toss a coin:
- heads it shows correct code
- tails it's showing previously iteration of code gen code, but the new code is in, so the debugger will at some point get confused
- medusae it's showing previous iteration of code gen code, but new code hasn't been propagated, and you need to do some arcane rituals to make it work.
Hell, even as a user of codegen libs, updating codegen libs caused miscompilation because it was still caching the previous codegen version.
They require 2.0, which is the only version that is actually useful, since it supports .NET Framework 4.x.v
> web benchmarks
https://www.techempower.com/benchmarks/#hw=ph&test=composite...
The Tech Empower benchmarks do seem to reflect general state of Java Web Framework ecosystem with Vert.x being they hyper fast web framework and Spring being way slower.
If you take the standard template for any of these frameworks (both Java and C# and any other language) and you add authentication etc, the real performance will be 5-10% of the numbers reported in those benchmarks. Have a look through some of the weirdness in the implementations it's wild (and sometimes educational). The .NET team especially has done stuff specifically to get faster on those benchmarks.
Could you give me a pointer or two? I wondered about that myself, especially considering the massive improvement from "old" .NET to the core/kestrel based solutions - but a quick browsing a while ago mostly left me astonished how...well, for lack of a better word, banal most of the code was.
Agreed though, lack of all kinds of layers like auth, orm etc. are sadly a drawback of these kinds of benchmarks, if understandable - it would make comparability even trickier and has the danger of the comparison matrix of systems/frameworks/libraries exploding in size. But yeah, would be nice datapoints to have. :)
The custom BufferWriter stuff is pretty neat though, although also not really something most people will reach for. And there is more, like the caching of StringBuilders etc.
But it also doesn't use the actual HTTP server to build headers, but they just dump a string into the socket [2], feels a bit unrealistic to me. In general the BenchmarkApplication class [3] is full of non-standard stuff that you'd normally let the framework handle.
[1] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast... [2] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast... [3] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast...
Puh, yeah, I see what you mean, much the stuff in [2] and [3] is rather...bespoke, especially compared to the minimal and mvc targets. Not really what I'd consider "realistic" as per the benchmark's definition.
But TBH, I wouldn't consider [1] gross, on the contrary - simple, fast, lightweight Razor templating without other MVC (or other external) dependencies isn't that unusual a use case and something I've often thought ASP.NET Core was missing (even Razor Pages feel like overkill if you just want to quickly generate some dynamic HTML).
.NET is perfectly capable of standing on its own, and if there are specific areas that need improvement - this should serve as a push to further improve DB driver implementations and make ASP.NET Core more robust against various feature configurations. It is already much, much faster than Spring which is a good start, but it could be pushed further.
I'd like to note that neither Go nor Java are viable for high-performance programming in a way that C# is. Neither gives you the required low-level access, performance oriented APIs, ability to use zero-cost abstractions and platform control you get to have in .NET. You can get far with both, but not C++/Rust-far the way you can with C#.
Yeah, except if you are working on Web servers the quality of the framework and its supporting libraries is much more important than what code could theoretically achieve. What is the point of being able to 200 mph when you only ever drive up to 30mph.
> Neither gives you the required low-level access, performance oriented APIs, ability to use zero-cost abstractions.
Java is working on high performance abstractions, see Vector API (Simd) and project Valhalla (custom primitive types).
Sure C# has a theoretical leg up (for which it paid dearly by causing backwards incompatibility with reified generics) but most of the libraries don't use low-level access or SIMD optimizations or what not.
If you meant BenchmarksGame, then it's the other way around - Java is most competitive where it relies heavily on GC[0], and loses in other areas which require capability to write a low-level implementation[1] that C# provides.
The only places where there are C calls are pidigts[2] and regex-redux[3] benchmarks, in both of which the Java submissions have to import pre-generated or pre-made bindings to GMP and PCRE2 respectively. As do all other languages, with varying degrees of "preparation".
[0]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[1]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[2]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[3]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Even if you prohibit PCRE2, the .NET submissions using out-of-box Regex engine end up being about 4 times faster than Java.
Surprisingly, even though .NET's BigInteger is known for its inefficiency, it ends up being more memory efficient and marginally faster at pidigits than a Java submission that does not use GMP. The implementations are not line-by-line equivalent so may not be perfectly representative of performance of each BigInt implementation.
My point being - if you look at the submissions closer, the data gives much clearer picture and only supports the argument that C# is a very usable language for solving the tasks one would usually reach for C, C++ or Rust instead.
Sure looks like it's written in Java!
Look at all the programming language implementations that provide big integers by calling out to GMP. Why would it be "cheating" when available to all and done openly? Libraries matter.
2 of 10 (pidigits and regex-redux) allow use of widely available third party libraries — GMP, PCRE, RE2 — because there were language implementations that simply wrapped those libraries.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
It’s not that easy. I assume other programs hide the use in macros and libraries, in ways far beyond my simple understanding.
Where there are few enough programs that readers should check that the programs they compare seem appropriate for their purpose.
Why? Did you mean both use intrinsics or both don't?
> Sometimes, you just want to see
As-it-says, look for more-secs less-gz-source-code -- probably less optimised.
But it’s not that easy.
Filters some but maybe not all and maybe filters some wrongly.
If you don't think it's appropriate to compare the pi-digits and regex-redux programs, simply ignore them and compare the other 8!
Lombok is exceptionally backwards. You don't need getters/setters; and you should know how to try hashCode (and equals).
...and records exist
That's basically modern-day Java, with Lombok and other tidbits. Furthermore, if I recall correctly, Java has better performance on web benchmarks than C#.
> Had Java been better, Kotlin wouldn't need to be invented.
Kotlin was invented to make a sugary version of Java, and thus drive more JetBrains sales. It got popular because Oracle got litigious. As someone who's been on the Java train for almost two decades, what usually happens, if any JVM Lang becomes too popular, Java has the tendency to reintegrate its features into itself.
> Whatever you like, find fun and makes you a productive and happy developer. There is nothing wrong in using C or C++. Or Python. Or Haskell.
Sure, assuming it fits the domain. Like, don't use Python for kernel dev or Java for some obscure ML/AI when you could use Python.