HN user

_old_dude_

804 karma
Posts0
Comments302
View on HN
No posts found.

I think pass by copy is a consequence of being modifiable.

The other solution is to stack allocate and pass a pointer but as i said, unlike in C#, i do not think it's possible to do that in Java.

In Go, you can stack allocate but when you send a pointer (that escapes), the compiler will heap allocate the object.

The usual GC tradeoff is between memory and CPU performance. If you set the memory max high, the GC will run less often, you get less pause time.

So I do not understand why it's a surprise that minimizing the pause time requires more memory. Is it because there is no knob to set either the max pause time or the max memory ?

I agree. And the next section is very clear that they want to kill the project.

  > For example, rather than proposing one single concrete JIT implementation,
  > it may make more sense for the PEP to describe a JIT infrastructure that
  > can support multiple implementation strategies.
  > Since many different and promising JIT tracing approaches continue to be proposed,
  > we believe the infrastructure should make it easy to experiment with and evaluate
  > those approaches within CPython rather than be highly coupled with a single strategy.
Allowing multiple strategies is far harder and as far as I know, JIT tracing is still unproven.

You need more than that for the example with setTimeout(). It requires to be able to freeze the stack and then go back later.

You need stackful coroutine (like goroutine) for that.

Parser generators are great in Python (Lark for me) so you can iterate fast and get a runtime spec of your grammar.

A hand-written recursive descent parser is something you do later when you start to industrialize your code, to get better error messages, make the parser incremental, etc.

Bison/ANTLR are code generators, they do not fit well in that model.

In C#, all instances have a class, so there is already a discriminant, the class itself.

In the article, the example with the switch works because it switches on the class of the instance.

In Scala 3, the inline keyword is part of the macro system.

When inline is used on a parameter, it instructs the compiler to inline the expression at the call site. If the expression is substantial, this creates considerable work for the JIT compiler.

Requesting inlining at the compiler level (as opposed to letting the JIT handle it) is risky unless you can guarantee that a later compiler phase will simplify the inlined code.

There's an important behavioral difference between Scala 2 and 3: in 2, @inline was merely a suggestion to the compiler, whereas in 3, the compiler unconditionally applies the inline keyword. Consequently, directly replacing @inline with inline when migrating from 2 to 3 is a mistake.

Yes, the version in Java is clearly less elegant. Java has map+lambda and compareTo (<=>) but no tuple assignemnt and no splat.

    record AppVersion(int major, int minor, int patch) implements Comparable<AppVersion> {
      public static AppVersion of(String version) {
        var array = Arrays.copyOf(Arrays.stream(version.split("\\.")).mapToInt(Integer::parseInt).toArray(), 3);
        return new AppVersion(array[0], array[1], array[2]);
      }

      public int compareTo(AppVersion other) {
        return Comparator.comparingInt(AppVersion::major)
            .thenComparingInt(AppVersion::minor)
            .thenComparingInt(AppVersion::patch)
            .compare(this, other);
      }

      public String toString() {
        return "%d.%d.%d".formatted(major, minor, patch);
      }
    }

For the record (sorry), I believe C# uses the clone operation because records support inheritance.

For me, this is where lies the design flaw, trying to support both inheritance and be immutability at the same time.

OOP is great for libraries but leads to overly complex codes for applications.

For a long time, Java was like, every classes is a library, i do not think it's a failure of OOP, it's a failure of Java.

But I'm optimistic, I choose to see recent additions like records and pattern matching has a step in the right direction.

I've just tried to change a field of an instance of a record using reflection, and it's not possible, even with setAccessible(true).

In Java, constants are declared as static final.

  static final Complex CONSTANT = new Complex(1, 2);
If you want a lazy initialized constant, you want a stable value
  static final StableValue<Complex> STABLE_VALUE = StableValue.of();

  Complex getLazyConstant() {
    return STABLE_VALUE.orElseGet(() -> new Complex(1, 2))
  }
If you want the fields of a constant to be constant too, Complex has to be declared has a record.

In JavaScript, a 'let' inside the initializer of a for loop is captured by value, all the others are captured by reference.

I think it's fair to call that semantics "implicit".

Parroting something i have heard at a Java conference several years ago, tail recursion remove stack frames but the security model is based on stack frames, so it has to be a JVM optimization, not a compiler optimization.

I've no idea if this fact still holds when the security manager will be removed.

Very true, in Java, at least in the last 20 years, inheritance is de-facto deprecated, all new bits and bolts like enums, annotations, lambdas or records do not support inheritance.

So you have to use composition.