HN user

piano

53 karma
Posts0
Comments41
View on HN
No posts found.

because you simply are stating that exponential processes are going to continue.

Exponential process continuing doesn't imply "we're going to get there soon" in any way, shape or form. The desired goal can still be arbitrarily far.

Well, the alternative is to learn an actual dozen of language

I would say that this is actually almost always preferable, for two reasons:

1. I believe it's generally good for programmers to know multiple languages, to be exposed to different ideas, ecosystems etc. This broadens worldviews, makes you think outside the box more often, etc.

2. Each of those languages will probably be better at what they do than D's subset. For example, D's GC isn't really one of the best ones out there. Its pure isn't the same thing as FP pure. Its move semantics is crap compared to Rust (probably even C++ does them better). The quality of the borrow-checking remains to be seen but frankly I'm skeptical, it'll probably follow the same pattern as the other features.

- Pure functions: these allow you to statically guarantee that a piece of code doesn't perform any IO and is a completely deterministic function of its inputs.

Is this actually true? As far as I know D's pure isn't the same as eg. Haskell pure, it only prevents modifications of global state, but you can still touch data referenced by arguments. I haven't done much D though so I'm not sure what the semantics really are...

but I prefer Go's culture much more

To me, Go culture is very arrogant, so much in fact that it almost reminds me of some Lispers of old.

Unfortunately similar thing can be said about Rust. However, in Rust, most of the crap seems to be comming from zealous newcommers and a loud minority, while the leadership and people involved seem relatively humble (or at least not too arrogant). In Go, OTOH, the arrogance seems to be stemming all the way from the top, judging from some talks & blogs by Pike, Cheney et al. Pike in particular seems to me to be a very arrogant, unpleasant person. I respect him very much as an engineer, but I will never like the way he speaks, promotes Go and spreads FUD about other languages.

Go is designed to do concurrency via message passing, not shared memory.

... and yet experienced gophers will criticize newcomer's code for using channels too much and they will tell you you need to use traditional stupid shared memory approach instead of channels in many cases.

Suppose Bob's codebase has a structure implA that implements interface A, and you want to use in terms of its interface. If the language requires Bob to declare implA as an implementation of A, you have to persuade him to do so in his codebase.

Not necessarily, in some lanugages you can add an interface to type even if the type is foreign and you only control the interface. I believe this can be done in Swift, Rust, F# and quite likely some others...

The thing I love about Go is its fundamental clarity. It's very upfront and literal. I find it easy to understand what is happening in any particular bit of code.

When reading Go codebase I'm not familiar with, I'm very often having a hard time figuring which interfaces go with which structs. As in "Oh, this function accepts interface Foo, which is implemented by which structures?" and then I have go on a adventure throughout the codebase to figure out what structures go in there. Really annoying.

In a language whose intention is to be explicit and easy to read (as opposed to write) I can't understand for the life of me why the authors chose to make interface implementations implicit. It seems like a decision that pretty much only has downsides and which is contrary to the overall aim. I just don't get it.

Yup, and besides, Go has the unsafe (https://golang.org/pkg/unsafe/) package, which allows for basically the same sort of unsafety as Rust's unsafe.

In fact, I would say Rust is typically more safe than Go, because in Rust you can mark any code as unsafe, it doesn't necessarily have to involve unsafe pointers. For example in Rust FFI functions are typically marked unsafe even if they don't involve pointers. There's no way to do that in Go.

Another example is strings: Rust ensures that strings are always valid UTF-8 by marking any function that could break that as unsafe. OTOH in Go you strings can contain invalid UTF-8 if I recall correctly.

The number of stars on GitHub is significant because most people whose opinion you’d care about are on GitHub, they wouldn’t star project that they were not interested in and there aren’t widespread fake accounts.

I am on Github and have been active in FOSS for years and yet I rarely star any projects at all, Github stars to me seem like vanity (just like likes on Facebook) indicative of perhaps hype but not of value.

In languages with termination analysis and dependent types, the source code _is_ the proof and it's verified by the compiler. Basically when such a program compiles, it's proved to be correct according to the specification.

Of course this still leaves space for bugs outside the program itself which still may influence it, such as bugs in the operating system or firmware or the like. Which may be prevented by having a formally verified OS too :)

But even in such a case, there might still be hardware errors (electrical noise, for example). Which is why for example spacecrafts or critical industry machinery double or triple their whole architectures. In such case the formally verified software runs on eg. three instances simulatenously and these instances cross-check each other's results all the time. When a hardware fault occurs (a bit randomly flipped in memory for example), they find out they're not matching and re-calculate.

That's as close as you can get to zero bugs.

Sure, you can’t in the general abstract case, but my exact point is that you can do this in practice, for programs which we actually write.

No, it can't be done with testing even for practical everyday programs, precisely because you never know how much your program is crossing into the "abstract general case" and which parts of it are more general than you think. Very often the cause of bugs is precisely this - that some part of a program behaves in a more general / less restricted way than the programmer thought.

It can be done with formal verification, but that's a whole another story.

The previous poster is correct. Software cannot be proven to be bug-free.

Yes, it can, that's what the whole formally verified software branch is about. Of course, even with formally verified software, there can be failures caused by external factors such as faults in hardware etc. But some piece of software itself absolutely can be proved to be correct (ie. bug-free). It just takes special approaches such as programming languages amenable to formal proofs (eg. Idris).

Software is usually written in bug-inducing ways and using languages that hinder formal verification not because provably bug-free software is impossible but because it is typically too costly and difficult to write.

The thing about Electron - and the thing that Electron fanboys either don't realize or don't care - is that with Electron, the company/vendor wins at the expense of users, who have to put up with their "application". No one really likes Elecrton apart from the vendor/developer and the most fanatic fanboys. Everyone else at best doesn't mind Electron.

If an Electron "application" is decent, people typically like the features or the online service to which it's tied but its Electron base is something that people more or less tolerate, depending on the degree it irks them. It's just a huge tradeoff, that's all. It reminds me of some Java or Python desktop applications, it's a similar kind of tradeoff.

Hopefully it'll pass just like the previous fads.

Hey can you give what is the rationale behind the JS hate?

JS has its overhead in terms of data and, more severly, performance. Many people tend to put unecessary JS stuff like custom scrolling, needless animations and needless interactivity, etc. This stuff more often than not just ends up getting in the way of normal browser function and is of questionable benefit or none at all.

I am building a website that relies heavily on JS. What should I be aware to steer away from the JS hate?

Don't add any JS interactivity that only makes a website "look cooler"* and that's not actually critical to your website's functioning. For example, stuff like google maps needs javascript. Stuff like blog most likely doesn't.

Remember to try out how your website works on a device with weak hardware and slow connection. This will not only make it far more accessible for people with older hardware, it will make better for recent hardware as well.

*) today's expression would probably be "rich user experince" or somesuch, but the meaning is the same - it's just vanity

But people need to feel productive quickly with a language, otherwise they'll drop it and move to something else which makes them feel that way.

Yes, I agree, but that's not the full picture. People want a language in which they can be productive quickly, but once they master it, they, or at least some of them, will then look into quality and performance. Languages like JavaScript or Python (and even Go to some extent) are popular and easy to pick up, but there's not much room for further progress. JavaScript is already stretched to its absolute limits when it comes to performance and it's still not performing very well. And when it comes to quality, well, TypeScript is a thing for a reason.

I don't believe Rust will ever be as much of a language for the masses as JS, but it has a good chance to become a niche language for those who need or want more performance and/or quality than they can get with langs like JS or Python.

In Rust, if I want to write a similar thing, a HPACK decoder that returns both `io::Error` and `HPACK::DecodeError` for example, I need come up with another `Result` type that wraps both errors. This can sometime be tiring and makes the code inflexible (As one simple change to the `Result` may effect the entire call chain up and down).

Well there's stuff like error-chain to take care of the boilerplate...

Also, I believe you could define the equivalent of Go error in Rust as a trait and box it (ie. a trait object). It could be used much the same way as in Go with the additional benefit of Result being a sum type. I'm personally not a big fan of this approach but I guess it might work...

This attitude is fine for personal projects, but it does not scale when working with other people.

True, but the same is true of Go, which may be surprising to people. Despite its claims, Go didn't solve this problem.

One reason is that larger projects typically start to invent their own abstractions on top of the base language and Go is no exception here, in fact, what with its lack of some common abstractions, built-in support for code generation, frequent use of external add-ons (like go vet etc.), Go very much encourages this. And so you're going to have to learn specifics of larger projects just like with "complex" languages. The solution to this problem is meticulous and somewhat restricted code style standard, but that's a solution that works with "complex" languages just as well, in fact, I'd argue that even better.

The other reason is that the Go language is not just the Go language. That is, what with the lack of abstractions for error handling, code re-use, etc., people end up following a bunch of conventions, styles, patterns and using external tools (like the already mentioned go vet). And so in effect the language becomes "the base" + "lore". This is of course true of any language. With Go and early Java, for example, this becomes more pronounced, since the base part is very small, larger parts need to be taken care of by the "lore". This is why Design Patterns become so popular in the Java world. And this why it's not good to have the base part too small, which is the problem of Go. Of course, the other extreme is equally bad - that is, when the base part is too large, which is the problem of C++, where now "lore" has to take care of deprecating/removing language features.

I feel like the authors of Go decided to do the opposite of what C++ does and thought that since C++ is horrendous, doing the opposite would yield a great result. But unfortunatelly that's not the way things work. You can't just negate someone's bad approach and expect great results.

This is the n-th time I'm reading a suggestion to help Venezuela using Bitcoin/cryptocurrencies. I wonder whoever came up with this and whether there's any save reasoning behind it or if it's just a cryptonerd fantasy. Venezuela has a very low average internet connection speed, reportedly one of the lowest in the world. Sources I've found say it's no better than 2 Mbit/s. On that speed, downloading the current Bitcoin blockchain would take about 18 days.

With such an internet infrastracture, is the country even capable of maintaining an up-to-date connection to the bitcoin network?

Consider, however, that you are a computer scientist in 2012 that has been working in the field of image recognition using hand written algorthms for 20 years. You are the best in your field, highly respected. Your code has been refactored so many times that you think it is near perfect.

Then along comes a young PhD student named Alex, and presents a completely different way of doing image recognition. Instead of talking about "refactoring", the talks about "retraining" or "rewireing". Instead of talking about "software architecture" he talks about "network topology". While you are "unit testing", he is "regularizing". He is still refactoring and building software architecture, you say, but for him, those are less important.

Sounds like an intro to an unusually intellectual and a tad weird porn clip.

I use a terminal text editor when I'm doing something in the terminal, need to do a quick edit and don't want to have to switch away from the terminal into a GUI editor. For me that's typically commit messages and not-too-complex config files. In such cases using a terminal editor is simply more convenient...

It's not just the interface{} thing that's annoying. From my point of view, Go has way to many annoyances to be decent. No constness. No protection against copying. No compiler warnings. Crap error handling. Public/private denoted by uppercase/lowercase letter (WTF?). Implementation details leaking into the language - such as the "typed nil" nonsense. Struct and interface embedding is insane. Multiple returns from functions but no tuples. Needlessly complex `for` syntax, needlessly complex receiver syntax. Needless magic channel operators (they could've easily just been functions).

The tooling is also annoying with the most glaring deficiency being the lack of package versioning, which I believe is going to change (or it has already? I don't remember). And then there are tools like `go vet` which basically just attempt to make up for the compiler deficiencies in sub-par ways...

Go has a very nice runtime, but the language itself and the tooling feels extremely half-baked. I'm curious whether Go 2 will improve upon this.

But the way I see it, 95%+ of programs don't truly need generics.

Yes, they do. Pretty much 100% of programmers in statically-typed language need to use generic types/functions.

The "95%+" thing is just an observation that one typically needs to define type-parametrized structures of function very seldom. This is true, but it's in no way a good point against adding generics, because those remaining ~5% of cases are crucial for peaceful programming the other ~95% of times. That's why Go has built-in generic types, but as it's adoption grows, it's becomming clear they won't do any more...

In fact, I think most people asking for "generics" would have their true needs met by adding a few more built-ins to the language.

You argued against magic and now you'd like to add some more of it to the language...

Go tries to be non-magical, and sadly that can take much of the whimsy out of programming.

That's a weird thing to say seeing that Go very much is magical... Slices/arrays are magical and so are maps, channels and channel operators, the make() function and a whole bunch of other features.

I think your understanding is filpped. Generics are not a way to add magic, they remove magic. That's the whole point. Unfortunatelly, that which one doesn't understand may seem like magic to them even though it's not.

For example, compare a channel implementation in Go and Rust. In Go, the whole thing is pretty much magic. In Rust, it's just another struct that the compiler treats in no special way. Getting familiar with the magic of Go channels is only good for working with Go channels, the knowledge is not applicable for any other part of the language nor other languages. Learning generics on the other hand gives you better understanding of numerous features in multiple languages.

This is the root of the Go confusion.

The code will indeed still be easily understandable on a line-by-line basis, but larger units (functions, groups of functions, modules) then become harder to read and understand due to large amounts of noise. As you progress along to more advanced, larger codebases, with novice-style code you just pile boilerplate on top of boilerplate.

Larger Go codebases remind me of old versions of Java where they went as far as to embrace all the boilerplate and call it 'design patterns'. It's sad how Go designers recognized that Java code tends to be hard to read and generally bad, but apparently weren't really able to discern why that is. They decided to just blame it all on inheritance and exceptions.

(FTR I'm not advocating for inheritance or exceptions here, but believing that those are the root of Java's problems and simply omitting them will somehow magically make a language better is just naive & shortsighted.)