o11c

joined 2 years ago
[–] [email protected] 5 points 2 years ago

I would say that strings are one of the least inefficient things in the JVM. Yes, you pay double cost for ASCII, but the memory is contiguous unlike Object-heavy code where you have to pay double size cost and an indirection. Also, slicing is "free" unlike many other languages (though make sure you copy if the parent is going to die).

[–] [email protected] 15 points 2 years ago* (last edited 2 years ago) (1 children)

Java has never had a good reputation, lol. But seriously, by every possible measure it has superior competitors:

  • Compared to dynamically-typed or interpreted languages, Java performs better, but it requires a frankly ludicrous amount of extra typing.
  • Compared to AOT compiled languages, it performs poorly except in purely numeric code where it has the advantage of portable -march=native. Other code almost never can be optimized due to the mandatory memory overhead.
  • Compared to any language, Java lacks support for most forms of ownership that people actually intend, and makes them very difficult to implement them yourself. Of the 3 ownership policies it does support, GC is useless (solely a crutch for programmers who are too lazy or too incompetent to specify what they want), Weak is sabotaged by its relation to GC, and Unique is limited to local contexts and does not compose. (I don't consider Phantom and Soft to actually be distinct ownership types, just hooks for GC ownership)
  • In its own niche (static types + JIT + GC), C# is strictly superior as a language, due to supporting value types (although not all C# bothers to use them, at least you have the option of performance). The only disadvantage of C# is in its ecosystem: historically there were a lot of Windows-only libraries; also there were people specifically depending on Java's ecosystem.

Writing your new app in Java is still better than using Electron or something though.

[–] [email protected] 3 points 2 years ago* (last edited 2 years ago)

Some technical decisions that a lot of people seem to miss:

  • It is impossible to make TCP reliable, even if you encrypt everything. Random middleware will spam you with RSTs and break your client-server connections for no reason, and while you can tell your server firewall to ignore them, you can't expect clients to.
  • The internet backbone is designed mostly around TCP. Most UDP-based protocols do not gracefully degrade. Thus, your only reasonable choice is the one they have to deal with: QUIC/HTTP3. Use an existing library, don't roll your own.
  • Make sure your low-level UDP library is using sendmmsg/recvmmsg, not sendmsg/recvmsg. Without that you often get performance worse than TCP. A lot of libraries are lacking here! Some OSes need other methods, or might not provide any way to get good performance; I'm only familiar with the Linux solution.
  • Define your (application-layer) packet layout using data (fed to some kind of code generator), not manually-written code. Make sure your basic packet structuring code doesn't (i.e. make every packet declare its size, even if it's logically fixed size and you're absolutely sure that will never change). If you need multiple variable-sized fields, stick them all at the end and use indirection. To ensure compatibility, always ignore extra data and pad short packets with zeros (flexibility only at the end suffices). There are a lot of terrible serialization formats out there, even the ones used by major companies.
  • Write for the IPv6 stack only, and turn the IPV6_V6ONLY sockopt off to transparently handle IPv4 as if it were IPv6 (although it defaults to off, the local administrator can change that, so always take care of it in your code).
  • Never have clients connect to multiple servers during the course of a connection (you can separate real HTTP server for ahead-of-time downloads). You should write a proxy-like server that forwards packets appropriate to the lobby, the actual game server, etc. and only let clients even know about that proxy.
  • Note that internet routing is bad in parts of the world, so forward-only proxies are sometimes useful too!
[–] [email protected] -1 points 2 years ago (2 children)

The second, or early return/continue/break.

But don't forget the third option:

foo = null
if (bar != null)
    foo = bar.baz();

This is much more readable if nontrivial; the only downside is that this inhibits the practice of ubiquitous final.

Actually, doesn't Java allow lazy final if you don't initialize (that would require explicit else)? I speak too many languages ...

[–] [email protected] 8 points 2 years ago

and yet the very fact that you have to go out of your way to enable them means people don't use them like they should.

[–] [email protected] 2 points 2 years ago

I've been annoyed at this in Python sometimes, since its containers have some operations named only, some operator only, and some available as both.

C++'s standard containers mostly have useless operator overloads though, so its technical win here isn't particularly impressive. One thing you definitely notice when porting C++ code to other languages is just how many silly dances various APIs force you to use for common tasks.

[–] [email protected] 22 points 2 years ago (6 children)

The solution is quite simple though: dogfood.

Developers must test their website on a dialup connection, and on a computer with only 2GB of RAM. Use remote machines for compilation-like tasks.

[–] [email protected] 2 points 2 years ago

It's mostly relevant for a project you're not familiar with (perhaps it is/was someone else's project, or perhaps a project that's too large for a single user to be familiar with the entirety of), since it helps you figure out where a bug came from.

If you're familiar with the entire project you usually don't need it IME.

[–] [email protected] -2 points 2 years ago (2 children)

"Freedom to take away others' freedom" is not actually freedom.

[–] [email protected] 2 points 2 years ago (3 children)

The cases where you can use git pull --rebase have high overlap with the cases where git rebase is sane.

The important thing is when to avoid doing git push --force (almost always; if your remote is a personal fork you theoretically could just create an infinite number of similar branch names for your rebases). Though there are edge cases involving local/SSH clones.

view more: ‹ prev next ›