Hacker Newsnew | past | comments | ask | show | jobs | submit | throwaw199ay's commentslogin

> This is a false dichotomy.

No, React beginner tutorial implies learning JSX , then you need to compile JSX into JS. Vue.js does none of that. You just write Javascript and HTML. And yes, Vue.js also supports server-side rendering.


The argument is passing your source code through a REPL makes it significantly more difficult to learn? Learning JSX isn't any more difficult than learning Vue's template binding syntax.


You're completely ignoring the argument. React doesn't really tell you that you can just grab that file but even so you still need to get JSX processed.

It's all about the friction. Vue currently offers significantly less friction to jump into than React.


JS -> JSX is transpilation, not a REPL.


Yes, and the Babel REPL/CLI can do that transpilation.


One wouldn't normally use babel as a REPL. I don't think it even has one (asides from node's own REPL, which isn't normally part of using Babel). Have you ever interactively typed commands into Babel?


> I think it is no surprise that one goal of Go is coding at large where large teams are involved.

I don't buy that. There is no proof Go programming at large scales better than Java programming at large.

Go didn't reach the scale of Java programs yet. And no, Kub or Docker, while fairly large, are nothing compared to 15 y.o. multi-million line Java codebases. Go certainly needs less bureaucracy due to the ease of deployment, but it doesn't mean Go projects scale better in large teams.

> For single person projects that I think you are doing, many people want intellectually stimulating language where Go may fall short.

I really hate this kind of arguments. Features like generics aren't intellectually stimulating, they are here because people want to write type safe code. Context.Value(interface{})interface{} isn't type safe code.

Now tell me, what is more intellectually challenging? writing concurrent programs free of race conditions or generics?


> Go didn't reach the scale of Java programs yet. And no, Kub or Docker, while fairly large, are nothing compared to 15 y.o. multi-million line Java codebases.

I didn't claim Java projects do not scale. They do. I use Java all the time at my day job. I would use whatever makes sense. Maybe someday Rust is absolutely essential I would use it then.

> Features like generics aren't intellectually stimulating, they are here because people want to write type safe code.

When people need generics they can use languages with generics facility then. I am not arguing otherwise.


> When people need generics they can use languages with generics facility then. I am not arguing otherwise.

This is the point where Go's advocates disagree with its detractors. The latter tend to feel that you need generics (Just like you need to program in something higher level then assembly) far more frequently then they are told.


+1

I want intellectually appealing code, not intellectually torturous.


> The fact is a lot of people are perfectly fine current Go capabilities and prefer writing useful software solution as compared to debating on PL theories and community agendas.

How many? how many didn't use Go because it lacked of a sane type system? because Go relies way too much on runtime behavior (AKA type switches and reflection) to be called a modern statically typed language. In all my time using Java I never had to cast something once or use reflection, or to do a type assertion, all these are common practice in Go, especially when the std lib is now getting API like Context.Value(interface{})interface{}.

This isn't PL theory, these are flaws that aren't going anyway and will become more apparent as users will have to maintain all that "productive Go code" written 5/10 years ago. With Go the developers basically do the compiler's job manually. These problems are absolutely not going away, and people will write about how they ditched Go for these reasons.


You may not have used reflection in Java but we have a very large application in production which is heavily dependent on reflection. It is in use for many years and serves business purpose just fine. Could there be a better way? maybe, but a working solution now is better for our business than promised solution in remote future.


I think the striking point is that you're forced to use a throwaway to have an opinion.


I agree with you about Go's flaws. However, if you have never used a cast or reflection in Java, you have either not done much Java, or you have used libraries and frameworks that do the casts and reflection for you.


Absolutely. Many people will decide not to use Go for these reasons.

But others will come to the conclusion that things like complex name lookup rules, or generally too many possible interpretations of individual syntactical expressions, cause hugely greater mental load than any of Go's shortcomings.

That said, I have a lot of complaints about Go too. Especially error handling.


Almost every dependency injection framework in Java uses reflection extensively. And nearly every java project I've ever seen used one of them. Your claim that you didn't have to do reflection may be correct but I'm betting you were consuming code that used a lot of reflection.


Reflection is pretty predominant in java, even if you don't use it yourself. Many frameworks (like spring) rely on reflection to do their magic.


> Not enough Go code adds context like os.Remove does. Too much code does only

Well, the error interface is { Error()string } and gophers were told to use errors as values, not errors as type because supposedly "exceptions are bad". By providing context you are just re-inventing your own mediocre exception system. Why use errors as value at first place if you need context? just put exceptions in Go, therefore people don't need to use a third party library to wrap errors in order to trace the execution context.


I really don't miss having invisible control flow for expected conditions blowing up my programs with long stack traces.

There's a whole lot of space between "include useful context in errors" and "exceptions".

(And FWIW, Go does have exceptions, it just calls them panics, and has a culture not using them for "known knowns" error conditions.)


> I really don't miss having invisible control flow for expected conditions blowing up my programs with long stack traces.

As opposed to panics? Checked exceptions don't blow up in your face, you have to handle them. Nil errors and type errors might yet these also happen to Go. I see no difference with Java here. Go isn't better when it comes to error handling, in fact Go is extremely tedious when it comes to error handling.

> (And FWIW, Go does have exceptions, it just calls them panics, and has a culture not using them for "known knowns" error conditions.)

So Go has both(unchecked exceptions and errors as "value"), how does it make things better? it doesn't. If it did, the blog wouldn't be talking about people "handling errors the wrong way".


I've found it helpful to distinguish between errors that are program bugs and errors that are conditions of the outside world (network errors, invalid data, etc).

I think it depends somewhat on the kind of software you're writing.

Being very careful with errors is quite handy for a long-running server processes; maybe (maybe!) not so worth it for a program that starts and stops within the attention span of a single user.


errors that are program bugs and errors that are conditions of the outside world

That also happens to be the intended distinction between Java's checked and unchecked exceptions.


> you have to handle them

the definition of "handle" widely varies, to the point of making the exercise near meaningless.


> I really don't miss having invisible control flow for expected conditions blowing up my programs with long stack traces.

You mean outside of accidentally running into a nil, and having your program spontaneously abort?

Even worse, reliably testing for nil (`if (foo == nil)`) doesn't even save you because go's nils are typed. So `foo == nil` can actually return false even when foo is nil. Utter madness.


Running into a nil would be an "unexpected condition". In that case, an exception (panic, in Go lingo) is reasonable.

It is true that Go doesn't do as much as other languages to avoid nils. It's a small, unambitious language in some ways. (Like, it adds more typing than Python, not as much as rust or swift.)

    foo == nil
will always tell you the truth. The edge case that trips people up at first that I think you're thinking of is that storing a nil-pointer into an interface will not give you a nil interface:

     package main

    import "fmt"

    type Foo struct{}

    func (f *Foo) Do() { fmt.Println("do the foo", f) }

    type Doer interface {
        Do()
    }

    func main() {
        var foo *Foo = nil
        fmt.Println(foo == nil) // true
        var doer Doer = foo
        fmt.Println(doer == nil) // false, because doer is (nil,Foo)
        doer.Do()                // prints "do the foo <nil>"
    }
https://play.golang.org/p/Ul9cX34qfF

That's because an interface is a (pointer,type) pair, so even if the pointer is nil, the type being non-nil will make the pair non-nil.


I understand how and why this works. But the fact that you can write some form of

    var foo *Foo = nil
    var bar Bar  = foo
    
    foo == nil # true
    bar == nil # false
is, to be completely honest, completely ridiculous. It means you can perform a sanity check for nil values and still accidentally operate on a nil value.

Null references have been referred to by Tony Hoare as his billion-dollar mistake. We should not be reintroducing mistakes of this level of magnitude, and worse, compounding on them, in new languages invented with fifty years of hindsight.


It's because nil values aren't invalid the way they are in C. You can having a nil Object pointer but still call methods on it:

    func (o *Object) DoSomething() {
        if o == nil {
            fmt.Println("Nil implementation")
        }
        fmt.Println("Something with the members here")
    }
Whether or not this is a good idea would be a different discussion, but typed nil struct pointers don't automatically crash the way they do in C. Therefore, it is perfectly valid to have some interface implemented by what is a nil pointer to some object type. I've even used this a few times. nil only crashes when you try to write into a nil map and a few other operations. Even some operations you'd expect to crash are implemented in a way that they will not. For instance, you can append to a nil slice, and a new slice and underlying array will be allocated for you rather than crashing.

Go does not by any means solve the "billion-dollar mistake", and I'd still like to be able to put "non-nillable" on things, but it is less affected by it than C. (Which is damning with faint praise, certainly.)


You don't have to keep explaining the mechanism. I get the mechanism. But the fact that `foo == nil` can return false when foo is actually nil is indefensible. The fact that it crashes less than C does is not a defense here. Sorry.


But foo isn't nil.

I'll agree with the opinion that it can be confusing that an interface consists of two elements, the type and the value itself, and that the "== nil" check may not do what you initially expect, because the interface values are hidden below the surface of the abstraction the language provides. But it is not true to say that "the interface value is nil", because it factually isn't. To use psuedo-Go, since neither "Interface" nor the types are first-class values, Interface{ConcretePointerType, nil} does not and should not compare as equal to nil. There are values in memory corresponding to this interface value, and those values do not correspond to any interpretation of "nil" Go uses. We're talking about real numbers in real RAM here and a real specification of nil that corresponds to those real numbers in RAM; this is not a matter of opinion.

I don't know of any language that doesn't have a few dozen quirks of this sort buried in it. It can be pointed out as a legitimate criticism of the language, but it's not particularly a flaw relative to other languages. Either it's not possible to build a truly clean programming language that lacks this sort of quirk, or we're not very good at it.

Before replying to me with the language you believe lacks these quirks, please do me a favor and search for "$LANGUAGE quirk" and "$LANGUAGE gotcha" first, because that's the first thing I'm going to do. And it won't be a defense to me to explain how what you found is not really a quirk because you just have to properly understand the language, because that defense is true for this quirk of Go's too.


i think people get so tripped up by this because they expect equational reasoning to work:

   a = nil
   b = a
   // => b == nil, right? but no.
one of the devs on /r/golang posted he wished they had used a different keyword like "unset" to check for an empty interface, which would be much less intuitively confusing.

i agree all languages end up with quirks like this (can't get everything right without really using the language, and by then it's too late!), and in fact go is low on the quirk level in my opinion.

the other one i really wish i could change is that

    for i, x := range foo
doesn't give x a new binding each time through the loop. Confusing, and almost never the behavior you want.


    But the fact that `foo == nil` can return false when foo is actually nil is indefensible. 
You keep saying this, but it's not true.


Only because go has redefined the terms.

    …

    foo = nil
    bar = foo

    // this check may or may not evaluate as true
    if (bar == nil) {
       …
    }
Saying that `bar` here isn't actually equal to nil if it's an interface is tautological. It's not, but only because the language has defined this to be the case. Go could likewise define `1 == 2` to evaluate to true, and you could reuse the same semantic reasoning to defend it.

The point being argued is that it doesn't matter that go defines this to be the case, the point being argued is that it's surprising, frustrating, and can lead to bugs. Particularly when `bar` starts off as a pointer to a struct, but later is refactored to be an interface type. Code that used to work still compiles, but now encounters a runtime nil panic.


(See also my response to jerf, above.)

In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

For example, this C code will print "nope":

    float b = 3.5;
    int a = b;
    printf(a==3.5 ? "yup" : "nope\n");
So back to Go, sure, this is initially surprising, and most people get bit by it at first. Once you know about it, it's fine.

In practice I haven't encountered any refactoring bugs as you describe, though it is theoretically possible.

I personally don't see it as a big issue.

(In retrospect, Go could've help guide intuition better by using a new keyword like "unset" or something to test for the zero-value of interfaces, instead of overloading nil.)


> In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

While I haven't counted and compared, I suspect that in most programming languages, "a=b" being a non-error implies that either a and b are the same type and value, or that a and b are values that, if they are of different and comparable types, will compare equal.

There are certainly popular languages that do it the way you describe, but I don't think most languages do.


That's a fair point.


> In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

While this is true, in all of those other cases you have the benefit of compile-time type checking so cannot call a function on the wrong type.

With nil, you get runtime errors.


Go's nils aren't typed, it's just that an interface value can have a type and point at nil. Also, I've never run into this "problem" in all my time of using Go...


I think their views on this are changing from experience with the language. Part of the problem I think is that the way they wanted people to use the language isn't clearly explained on their posts about errors. Some how I read it over and over and I never quite get the gist of when they think I should create a custom error type or not.


Because Go considers errors to be values, and exceptions are control flow.


Errors must be handled, which means you always get control flow with them, even if it's just the primitive (if err != nil) -- in Go you just have to manually write the control flow instead of the language helping you.


Right - the control flow is explicit, and works the same as regular control flow.


But there is value in providing a different control flow for errors, which is why exceptions have become prevalent in most programming languages in the past decades.

The value is that your code's happy path is clean and not encumbered with error checks every ten lines, like we see in Go sources all the time.

Separating the happy path and the error handling in different sections of the code contributes to clean code, especially if exceptions are checked and cannot be ignored by the developer.


In my experience, separating the happy path from the error handling leads to unhandled errors. Just yesterday, one of our python projects (an API with about 600 endpoints) started barfing an error for non-parseable JSON because something at the top level caught it. I have no clue where it came from nor how to reproduce it. Had we been handling errors when and where they occur, I would have a vastly shorter debugging period in front of me.


> In my experience, separating the happy path from the error handling leads to unhandled errors.

No, the separation has nothing to do whether errors are handled or not.

If error handling is mandated by the compiler (e.g. checked exceptions), there will be no unhandled errors since the compiler will simply refuse to compile your code until you handle these errors.

Whether you handle these errors near the happy path or in a different section of the code is an orthogonal concern.


Or people will simply elect to use unchecked exceptions, and users will see stack traces frequently. In either case, Go programs don't seem to suffer from bugs in the error handling paths like Java and friends. YMMV.

I don't see the value in a clean happy path and a hidden error path.


> Or people will simply elect to use unchecked exceptions

Go already has unchecked exceptions. It's called "panic".


Ok? How does that relate to the discussion? What point are you intending to make?


It completely invalidates your argument. Your argument is that an error-handling system as described would be undesirable because it would result in developers misusing unchecked exceptions. Go already has unchecked exceptions in the form of `panic`.

So either developers are already abusing it, in which case go's current error-handling approach is no better than the one proposed according to your metric. Or developers have access to it but aren't abusing it, in which case there's no reason to expect they'd abuse it in a system where doing it the right way is even easier than it is today.

In my experience, users already do experience stack traces as it's embarrassingly easy to accidentally operate on a nil pointer.


I'm not sure whose argument that is, but it's not mine.


You realize people can simply scroll up to verify that, in fact, that is the exact argument you're making, right?


You're confused. My only point was that checked exceptions are only good when they're used. Better luck next time.


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: