Hacker News new | past | comments | ask | show | jobs | submit login

Reading this code almost makes me want to think about how differently I review Java than C or C++.

  ch = ++index < strlen ? str.charAt(index) : 0;
If I saw that code scattered across in some java code, I would immediately be like - "rewrite please".

But the same code fragment in C would be like - yeah, we need a bounds check, good job, can you make it a macro please.

The java default Float parser was somewhat of a complete perf headache when multi-threading, more than about single core consumption (till jdk8b96 - JDK-7032154), so in the past Hive has shipped with its own strod impl[1] to avoid the central lock in parseDouble.

Also it worked off a raw utf8 byte[] stream, which is more common coming out of a disk file or network serialization rather than a CharSequence.

[1] - https://github.com/apache/hive/blob/4446414f4478091db1eb20bc...




The real question is why C/C++ programmers accept code like that. You can write that same code in an easier-to-follow way, and the compiler will turn it into an identical binary.

Code should be written for humans.


Frameworks produced by Windows dev team are a very good example of that.

They could produce something that looks like Qt, OWL/VCL, or nowadays .NET like but in C++.

Instead they produce libraries where one is forced to use C low level details, mixed with Win32 and COM pointer handling and casts everywhere, not even MFC escapes it.

Not to count how many interactions of COM smart pointers that have come up with since COM exists.

C++/CX looked like they finally learned their way and would offer something similar to C++ Builder, but no that wasn't meant for us to enjoy it.

So now anyone doing UWP with C++, gets to manually edit IDL files without tooling support, and merge the generated files manually.

I really don't get their macho developer culture.


According to Steven Sinofsky, MFC being a thin wrapper around the underlying MFC was a deliberate design decision during its development. https://hardcoresoftware.learningbyshipping.com/p/010-our-bi...

In retrospect, do you feel it was it a bad idea to not use a heavier abstraction?


I am aware of it, hence my remark.

It was a bad idea versus what other compiler vendors had in their toolbox.

MFC only won because Microsoft is the OS vendor, and Borland lost it trying to fly too high.

Back in the MS-DOS and Windows 3.x very few would use Microsoft compilers, Borland and Watcom were the favourite.


> I really don't get their macho developer culture.

I'm inclined to not recognize that as a distinct culture and rather call it an infectious habit. Auditable, maintainable code is a skill, after all.


It is. Apart from ++index, this is literally the same as:

  let ch = if index < strlen then str.charAt(index) else 0
Eminently readable and less boring than long if/else chains in Python.


It's not. To be easily human-parsable you want to do one thing at a time. It's that incrementation that you've ommited that messes things up.

On a side note, having gotten used to newer languages, an option type sure is a nice thing.


You can write in a very similar way in python too if you want to. I think I'd argue this is cleaner syntax, even.

    >>> foo = 10
    >>> bar = foo if foo > 5 else 0
    >>> bar
    10
    >>> bar = foo if foo < 5 else 0
    >>> bar
    0


IDK,

"for ch in index:"

reads pretty cleanly to me.


People who care about correctness wouldn't be using C/C++ in the first place. The culture of those languages is performance above all else, and it only gets worse as more and more "moderates" move to memory-safe languages, leaving only the extremists left.


That is not an informed opinion at all. The C++ people I know ALL care about correctness... That's why they use C++. They want to make sure it's done correctly, and not left to some node package that barely works.


Agree, especially as there's so little upside to writing it this way. It isn't going to run any faster. The style emphasises code-density over readability, but density is only a virtue when it aids readability.

I'd far prefer:

    ++index;
    ch = index < strlen ? str.charAt(index) : 0;
I don't see a good reason to make it a macro, though.


    index += 1;
    if (index < strlen) {
      ch = str.charAt(index);
    } else {
      ch = 0;
    }
If I was using kotlin, I'd do it even cleaner:

    inline fun String.at(index: Int): Char? =
      if (index >= 0 && index < length) charAt(index)
      else null

    [...]

    index += 1
    ch = str.at(index) ?: 0;
The bytecode is exactly the same, but I’d argue it’s much cleaner


I haven't used kotlin, but where is length defined? Should it be a parameter to the function?


The above is an extension function(which is basically a member function of class not written in that class), which has an implicit `this` parameter. In other words `length` is actually `this.length`, just as it would be in a regular method.


To me, the original C-style code looks nicer than the Java.

C++:

    bool found_minus = (*p == '-');
    bool negative = false;
    if (found_minus) {
      ++p;
      negative = true;
      if (!is_integer(*p)) { // a negative sign must be followed by an integer
        return nullptr;
      }
    }
Java:

    int strlen = str.length();
    if (strlen == 0) {
        throw new NumberFormatException("empty String");
    }
    int index = 0;
    char ch = str.charAt(index);

    boolean negative = false;
    if (ch == '-') {
        negative = true;
        ch = ++index < strlen ? str.charAt(index) : 0;
        if (ch == 0) {
            throw new NumberFormatException("'-' cannot stand alone");
        }
    }


I suppose the main point I was trying to convey is that the code snippet gopalv quoted is not ugly because it's C-like. That ternary expression doesn't appear in the original C++ implementation at all. Many of the things people are complaining about—like relying on the return value of a prefix increment—are only in the Java version.


As someone who writes both C++ and C# I disagree around writing C/C++ in this way. (I am talking specifically about the side effect to 'index', not the use of a tertiary operator which is fine here)

I have seen far too many bugs creep in this way. I feel like C/C++ induce a desire to keep the code as short as possible and being 'clever'; even I often feel the need to do that in C++ when I am happy to write a more readable version in other programming languages.

The bugs are also hard to spot when skimming through the code: When there's a lot of code you will often miss the ++ on the 'index' as it's a long line compared to having '++index' on its own line.

Another good 'pet peeve' of mine is the following construct:

  for(int i = 10; i--;)
    // Do something until 'i' reaches 0
So many off-by-one errors...


the irony is that there is a bounds check already within the str.charAt() method...


That throws an exception though, while this code is trying to return 0. The java "fix" would be to add a charAtOrDefault(), but that doesn't seem to exist.

The source of charAt is also interesting because it manually bounds checks while the array access into the underlying char[] has its own bounds check. I'm not sure why having the separate exception is better than letting the array access throw directly?

https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/19fb8f93c...


Agreed. Though catching and handling that exception maybe more performant if majority of those indexes are within the bounds of the array.

>> I'm not sure why having the separate exception is better than letting the array access throw directly?

(1) The original String charAt method (Sun/Oracle) had to account for an offset and an index. The exception from the bounds check on the underlying char[] would be misleading/confusing... and therefore the birth of the seperate StringIndexOutOfBoundsException

Source: http://www.docjar.com/html/api/java/lang/String.java.html

(2) Because of the above and for backward compatibility, the OpenJDK is doing the same exception handling... sometimes it pays to review the original source code to get some context and rationale to the OpenJDK version.


Oh that makes sense, I had forgotten about the old substring sharing optimization.


I disagree, why exactly would it need to be re-written because it's in Java? Does the language matter at all? To me this piece of code is concise, I immediately recognized it as a bounds check. If you re-write this to add braces, newlines, the if statement... just creates more cognitive load in favor of? To me this little line is perfect, it does exactly what it is supposed to do and it doesn't hide its intent.


If being more concise was always better for cognitive load, we'd all be writing APL.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: