Yet another Go thread


  • Considered Harmful

    @Arnavion said:

    You have the freedom to turn your cow into a sheep when you point to it.

    ...And this makes sense... When exactly?

    Seriously, this is the best example you can come up with? If anything it illustrates the problem: when is it logical for the set of things a Foo can do to be different from the set of things a Foo* can do?



  • Ok I'm going to read Papering's novel and reply to some points.

    @paperwing said:

    you are not forced to handle the error in an error-handling-only codepath (in contrast, try and catch branches enforce exactly this), meaning you can even have multiple errors in flight at the same time (i.e. store them in different variables), and be able to do other stuff before you handle or return the errors. In contrast, when you catch an exception, you have to handle it there and then (or re-throw it).

    Exceptions are just objects in C#. You can do something like this no problem:

    List<Exception> exceptions = new List<Exception>();
    
    foreach (string line in dataFile)
    {
    	try
    	{
    		ProcessLine(line);
    	}
    	catch (Exception e)
    	{
    		exceptions.Add(e);
    	}
    }
    
    // do something with exceptions after-the-fact

    The "problem" you're describing isn't really a problem; just a lack of imagination on your part. Or a misconception: you seem to think the code inside a catch{} block is a lot more isolated than it actually is.

    @paperwing said:

    (and actually, one could easily patch the go vet tool to print warnings for ignored error return values, but I don't think it would be very useful. People check their return values.)

    And people are never forgetful. And companies never hire under-educated interns to work on code. And people never work in languages they aren't 100% familiar with.

    So it's enough to just rely on "people do this, just trust me!"

    @paperwing said:

    But if you're writing a program that is gonna be presented to a user with little to no programming ability (and especially with no incentive to debug your code), then why show them a stacktrace at all?

    Good question. Is this something you're suggesting happens?

    @paperwing said:

    I, for one, am sick of all those python (and sometimes, GTK) programs on my computer that vomit a stacktrace whenever they do something stupid.

    First of all, you don't have to specifically state you're just one person. We can assume you're one person.

    Secondly, maybe you're just using shitty software. Finished, non-shitty software doesn't show stack traces to users.

    @paperwing said:

    But don't expect the users of your programs to have the enthusiasm to debug your code (even if they have the ability to).

    I'm mystified by your assumption that exception stack traces are supposed to be shown to end-users of the software. Where did you get this from?

    @paperwing said:

    For debugging, use strategically placed fmt.Printf calls.

    "Golang is a brand new state-of-the-art programming language designed for the 21st century! Debuggers? What are those?"

    Sheesh.

    @paperwing said:

    Or call panic, if you desperately need a stacktrace.

    Wouldn't it be nice if you had a debugger, so you didn't have to violently kill your program just to see a stack trace? Wouldn't it be awesome if you could break your program, look at the stack trace, then start running it again? Too bad these amazing science fiction technologies are so far in the future.

    @paperwing said:

    Cross-compiling works for go code only, because in the toolchain, mostly only the go compilers are designed in a way to support sane cross-compiling. It would be non-trivial to get gcc to painlessly cross-compile for every supported platform, out of the box.

    And Go developers are too fucking lazy to do something that isn't trivial!

    @paperwing said:

    Now, any go code that uses cgo (i.e. calls c code) has to use the gcc compiler to compile the C code. The last time I checked, the net package uses cgo, therefore if you're using net or net/http, etc, then you basically can't use cross-compiling, as far as I can tell.

    So you can cross-compile, as long as your program doesn't do anything useful at all. Gotcha.

    @paperwing said:

    The root of the issue is that gcc is a PITA to set up to cross-compile, especially across operating systems where you have to supply the system specific libc header files and whatnot. I tried to cross-compile c code from linux to windows once. It's not a pleasant trip.
    But otherwise, this might give you some guidelines, even if you're trying to do it the other way around:

    Wouldn't it be great if we have a type of program that could set up a computer to run other programs? Like installing an appliance? We could call it a ... installpliancer! Too bad science fiction technology like that is decades away.

    @paperwing said:

    True, go doesn't have constructors, because constructors are just an unnecessary special case of functions.

    (I know other people have addressed this already.) Nobody's going to debate that constructors are a special case of functions, but "unnecessary"? You be crazy, bro.

    Sometimes classes have state. Sometimes classes MUST have state to mean anything at all. (See the nuclear missile aiming class example a few posts up.) Allowing a programmer to instantiate a class that requires state without requiring them to provide the state is a recipe for disaster.

    It would be slightly better if Go had a way to guarantee EVERY class had a "NewFoo()" function and then the compiler threw an error if you instantiated a class without calling "NewFoo()" but... oh wait, you've just reinvented constructors.

    @paperwing said:

    Foo and Bar are exported types (they are capitalized),

    We've talked in other threads about how moronic the concept of "capitalization dictates visibility" is. It's moronic.

    @paperwing said:

    Name your function differently.

    Translation: the writers of Go's linker were either idiots or lazy fuckers.

    The linker in languages that doesn't suck identifies functions both by their name and their argument list-- how else would dynamic libraries work? Since they're already using the argument list to identify the function, there's no problem having two functions with the same human-readable name. The linker already has to tell the two functions apart based on argument list.

    Ah! But if I recall from another thread, Go doesn't allow dynamically-linked code at all! Because no program ever would want, say, extensibility. And you better go out of your way to defeat all those optimizations those operating system guys put in for managing shared library memory-- fuck those operating system guys!

    @paperwing said:

    the uncapitalized print and println functions (without any package qualifier either) are there for bootstrapping purposes. They aren't intended for general usage, they're there to build the go environment more easily. Use the fmt package instead. See these: http://golang.org/ref/spec#Bootstrapping

    Wow. So one page says "these functions are deprecated, don't rely on them", but the documentation for those functions says nothing at all about them being deprecated. Even Go's documentation sucks.

    @paperwing said:

    False. The go compiler doesn't enforce whitespace conventions at all, it's not supposed to. It does something related, though, namely, it automatically inserts semicolons into the code where it's appropriate, so that the later compiler passes can parse it.

    False. Go doesn't do Foo. But what it does do is Foo.

    @paperwing said:

    I wrote a prototype text editor (as in, the actual text control part, and the inmemory editor too) in go, using Go-SDL (an sdl binding for go).

    I literally can't think of a worse environment to write a text editor in than an OpenGL game library and Go. Congratulations. You've earned "dumbest software idea of the century".

    @paperwing said:

    I suggest that before you make observations like these, check your facts, check the compiler, and maybe read stuff about go on reddit, hackernews, or the mailing list. Lots of these points were discussed at length already.

    The problem is this community has brought up SO MANY awful ideas in Go that, even if a portion of those awful ideas are incorrect, it still doens't make Go look much less-awful.



  • @morbiuswilters said:

    Follow-up question: if the "methods" aren't bound to the objects themselves, and there's no overloading of methods, then how do you keep from having a bunch of conflicting function names in the global namespace?

    The syntax for class methods in Go looks similar to free functions, and like struct functions in C, class methods in Go are defined outside the body of the class. But otherwise, they function identically to C++ methods.



  • @joe.edwards said:

    @Arnavion said:
    You have the freedom to turn your cow into a sheep when you point to it.

    ...And this makes sense... When exactly?

    Seriously, this is the best example you can come up with? If anything it illustrates the problem: when is it logical for the set of things a Foo can do to be different from the set of things a Foo* can do?

    Don't ask me man, I'm the OP. I was just clarifying for morbs.



  • @Arnavion said:

    Pointless quoting and paraphrasing

    Look, since you aren't very smart, I'll help you out with a chart:

    Builder OS Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD
    Target OS Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD Windows Mac Linux Plan9 FreeBSD OpenBSD NetBSD
    Requires MSYS No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No
    Requires Microsoft Visual Studio No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No
    Requires GCC No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No


  • @joe.edwards said:

    @Arnavion said:
    You have the freedom to turn your cow into a sheep when you point to it.

    ...And this makes sense... When exactly?

    Seriously, this is the best example you can come up with? If anything it illustrates the problem: when is it logical for the set of things a Foo can do to be different from the set of things a Foo* can do?

    Pointer recievers are required to CHANGE data. You could logically have a Set method on a type defined as *int, but not on a type defined as int.


  • So... we're saying that the only thing that determines whether something is externally visible is whether it is lowercase or uppercase?  Sheesh.


  • Considered Harmful

    @Arnavion said:

    Don't ask me man, I'm the OP

    Sorry, got you confused with one of the staunch defenders.



  • @Sutherlands said:

    So... we're saying that the only thing that determines whether something is externally visible is whether it is lowercase or uppercase?  Sheesh.

    We've been over this about eighty thousand times. Yes.


  • Considered Harmful

    @Sutherlands said:

    So... we're saying that the only thing that determines whether something is externally visible is whether it is lowercase or uppercase?  Sheesh.

    It's really just codifying naming convention into law. It's kind of nasty but I actually find the idea of forced consistency appealing.

    In C# I use _prefixedCamel for private instance members, regularCamel for locals and parameters, PascalCase for anything public or protected. If I could make the build break if one of our team members violated this convention, I would turn that option on.



  • @Ben L. said:

    Look, since you aren't very smart, I'll help you out with a chart:

    Thanks for making a huge-ass table that says exactly the same thing I said.

    Also your chart is disingenous, since compiling for Linux on Windows requires GCC _sometimes_ (if what paperwing says is true about net/http, etc.).



  • @joe.edwards said:

    If I could make the build break if one of our team members violated this convention, I would turn that option on.

    BuildCop and StyleCop.


  • Considered Harmful

    @Arnavion said:

    @joe.edwards said:
    If I could make the build break if one of our team members violated this convention, I would turn that option on.

    BuildCop and StyleCop.

    I knew FXCop and StyleCop but not BuildCop, maybe this one will be more configurable. Of course our codebase is several thousand code files strong (and still growing), so doing this retroactively will be a huge pain in the ass. Ideally the tool would have prevented the situation from occurring.



  • @Ben L. said:

    Pointer recievers are required to CHANGE data. You could logically have a Set method on a type defined as *int, but not on a type defined as int.

    I believe that is covered by the = operator (combined with the * operator), which Go already has. What other operations can you think of that justify this language feature?



  • @Ben L. said:

    @Sutherlands said:

    So... we're saying that the only thing that determines whether something is externally visible is whether it is lowercase or uppercase?  Sheesh.

    We've been over this about eighty thousand times. Yes.
    In this thread or in some magical fairy thread that I haven't read?  Because in this thread I don't even see a definitive yes before this post.



  • @joe.edwards said:

    It's really just codifying naming convention into law. It's kind of nasty but I actually find the idea of forced consistency appealing.

    I'm not opposed to the concept, but as Blakey pointed out in the past, how does this work with Unicode names from languages that don't have a capital letter?



  • @Sutherlands said:

    ...some magical fairy thread...

    No, it's not in dhromed's My Little Ponies thread, either, but it was mentioned a few times before when we were making fun of Go.



  • @joe.edwards said:

    @Sutherlands said:

    So... we're saying that the only thing that determines whether something is externally visible is whether it is lowercase or uppercase?  Sheesh.

    It's really just codifying naming convention into law. It's kind of nasty but I actually find the idea of forced consistency appealing.

    In C# I use _prefixedCamel for private instance members, regularCamel for locals and parameters, PascalCase for anything public or protected. If I could make the build break if one of our team members violated this convention, I would turn that option on.

    It's really nasty.  There are (as shown) other ways of doing it.  Also, Reflector.  It's better than any of the Cops.

    Interesting side-story: A group that provides DLLs for our web team recently went through and made it mandatory for a check-in to not have any warnings.  Because of this, a dev went through and "fixed" all the capitalization errors... breaking the DLL for us, since, you know, none of the variable names matched.  He didn't think to question why they were forcing this, but just made the changes...



  • @Sutherlands said:

    In this thread or in some magical fairy thread that I haven't read? Because in this thread I don't even see a definitive yes before this post.

    In this thread it was only mentioned once in passing in the middle of the novel.

    We've discussed it in the past in one of Ben L's threads... hang on... here.



  • @Sutherlands said:

    Also, Reflector.  It's better than any of the Cops.

    The cops are just that - cops. They make sure no one can break the rules (pre-checkin hook). Reflector is like that fairy on your shoulder that stops you from getting in trouble with the cops in the first place. But some people don't believe in fairies, which is why you still need the cops.



  • @Arnavion said:

    Filed under: I have a fairy on my shoulder

    I wondered where dhromed was today.



  • @Arnavion said:

    @Sutherlands said:
    Also, Reflector.  It's better than any of the Cops.

    The cops are just that - cops. They make sure no one can break the rules (pre-checkin hook). Reflector is like that fairy on your shoulder that stops you from getting in trouble with the cops in the first place. But some people don't believe in fairies, which is why you still need the cops.
    And by Reflector I mean Resharper.  And you can enforce that by creating a TFS hook.



  • Oh, right. I was talking about Resharper too.

    But do you mean that Resharper can be run in a pre-checkin hook? I didn't know that.



  • @Arnavion said:

    Oh, right. I was talking about Resharper too.

    But do you mean that Resharper can be run in a pre-checkin hook? I didn't know that.

    That's what I read.  I haven't done it myself.


  • Yeah, I guess Go binaries would be portable across Linux distros since they're statically linked. The main reason binaries aren't portable across distros is that one decides to use /lib, one uses /usr/lib, one uses /var/lib, one uses /usr/share/lib, etc.



  • @MiffTheFox said:

    Yeah, I guess Go binaries would be portable across Linux distros since they're statically linked. The main reason binaries aren't portable across distros is that one decides to use /lib, one uses /usr/lib, one uses /var/lib, one uses /usr/share/lib, etc.

    Or different versions of the libraries which have different ABIs.

    Does Go re-implement libc? Or does it statically link it (which you're not supposed to do with glibc)? I assumed Go was probably creating wrappers around core C libraries instead of re-implementing them entirely in Go, which would be pretty WTFy. I thought the static linking just applied to object files generated by Go.



  • Hello again. First, yes, my previous post was long. Umm, I guess one should only read the parts that interest them most. But yeah, it would have been better to answer more succintly.

    I won't answer every reply I got, I don't have enough time for that. Especially not the more aggressive ones.

    Unwinding the logical stack is hard? Enforcement through a system of checked exceptions is hard?

    Consider this: you have several goroutines, all of them have resources open, like network sockets, or maybe they use some amount of locking. Closing/unlocking these resources should be done in finally calls, or deferred calls in go's case, that's not a problem so far.

    What happens if a goroutine suddenly gets a fatal error and can't continue? Call panic. The only that goroutine's stack unwinds, and the whole program crashes. Okay, what if I don't want the program to crash, and only want that goroutine to stop, but let the rest of the program continue? Put a deferred recover call to the beginning of the goroutine.

    What if I do want to bring down the whole program when a goroutine needs to stop, but also clean up every other goroutine that needs cleanup (i.e. close sockets, unlock locks, flush files to disk, etc)? This is what I'm having trouble figuring out, and I haven't asked for help with it yet. So far this is what I've come up with: when a goroutine can't continue, it sends a message to every other goroutine that it's time to panic. Then every goroutine unwinds its stack, recovers at the bottom, and signals to the main thread. The main thread waits for everyone, and exits the program.

    Depending on what the goroutines are doing, it might not be easy to have them constantly listen to a channel to anticipate a panic request. If the goroutine is just running a forever loop and draining a channel, or waiting on multiple channels, it's easy. If it's constantly bouncing around multiple functions that all block on different conditions, then that's trickier.

    The programmer is forced to not ignore that an error might be returned. He cannot call funcReturns2Things() without atleast making a token effort to receive the possible error. This example is almost identical to the one I gave in the OP, by the way. And it breaks horribly if you have a funcThatReturns1Thing that only returns an error. Again, the example is in the OP.

    if you want to ignore some returned values, use an underscore:

    a, _ = funcReturns2Things()
    

    Again, this is what you should do regardless whether the second value is an error or has a different type. This isn't enforced because the compiler wants to force people to check the returned errors, it's enforced because the programmer should know the API of the function, i.e. what it returns and what it takes.

    The bug is not necessarily unrecoverable. I still want to see its strack trace.

    I totally forgot about these.


    For any struct with a non-trivial initialization, NewFoo is going to have a bunch of code in it. If I define a NewFoo, I would want the programmer to be unable to call new(Foo). But in Go, even if I make NewFoo, the programmer can still call new(Foo) and get a Foo instance that hasn't run the code in NewFoo. Hence my point about throwing invariants out of the window.

    When a method or function you wrote gets called (one that handles a Foo), then check whether it's empty or not. If it's empty (i.e. if foo is a pointer, then foo == nil, or if foo is a value, then foo == Foo{}), then you can return an error that it's not initialized properly (or call panic if it's appropriate, it depends). If none of its fields are exported, then there is no way to set the struct to an invalid state outside the package. The only case you have to handle is an empty Foo, because new(Foo) (and every other declaration/allocation) always zeroes out the variable in question.

    Other than that, it's true that you can't really enforce the use of NewFoo, other than documenting it. People should check the documentation before using other people's code anyway; and you should document how to initialize Foo (or make the zero value immediately usable).

    Yes, this is the standard argument against function overloading, where the argument list is merged into the function name. [snip] However in the case of the type Foo, you'd have to go with NewFoo, MakeFoo, CreateFoo, InstantiateFoo. This gets ridiculous pretty fast. The alternative as I said is to merge the argument list into the function name. NewFooFromDatabaseRow, NewFooFromUserInput, NewFooFromFile. Ugh.

    Some cases of those variants can be mitigated by better design: if you can handle DatabaseRow, UserInput, and File the same (or similar enough) way inside NewFoo, then simply take an interface (like io.Reader), and have one function that does the initialization. There are a lot of features in go that prompt the programmer to change their programming style to one that suits the language more; it is uncommon that you need so many different constructors like in other languages. Look at go stdlib code if you don't believe me. It's pretty readable, unlike Java's stdlib.

    I was talking about fmt.Printf and fmt.Println. I was not giving valid Go examples (C-like pseudocode). Also there's a typo in there. I meant to say that the programmer would have to put "\n" in all his printf calls (not println).

    Oh, sorry, I thought you meant the uncapitalized ones. Yes, you have to put "\n" in the formatting when you call Printf. And Println takes varargs too, by the way. So does Print (and Printf, as you correctly claimed). I think these three functions cover most use cases adequately, and when I realize I need a specific format, I usually remember to put a terminating \n into the format. But most of the time I use Println.

    Or they could just be defined as methods of the string type.

    If they let user code define methods on basic types, then in big codebases it would be hard to track down and maintain exactly what methods were defined on which type, because the methods would be distributed among many packages. Imagine what would happen if you want to import an 3rd party package that defines a method on int, and you already have a different method on it with the same name (and lots of code that depends on that name and interface, etc).

    If they disallow that (like they do now), then they, the language devs, would have to give methods to basic types, and since they can't know about every possible interface in existance beforehand, then they'll leave out some potentially useful methods. And then you're forced to make your own type anyways, to give them the methods you want (only for that new type you made, not touching the basic types).

    So, I think the alternatives are worse than how things are.

    Perhaps I'm very OOP in my thinking, but I'd rather have my methods scoped to the type they work on (C# way), rather that be free functions that can work on many types from disparate inheritance trees (C++ STL).

    I understand what you mean with C++ in context, but I don't understand how that relates to go. Go doesn't have inheritance.

    I'm not sure how "It was a pain to install tooling on Windows. SDL had a bug on Windows." translates to "Go's Windows support is on par for its support for Linux."

    I meant that I had the least amount of problems with go, out of all the parts I had to work with on windows. The conclusions I drew from that specific experience with go on windows was this:

    • compilers work
    • cgo works
    • threads/goroutines work
    • calling Win32 graphics API works

    I can't really comment on the symlink issue that was reported to be fixed, and that you still found it unfixed. Have you checked which version it was fixed in, and the version you had installed? Go1.1 was released recently.

    (And the bug I had to fix was how goroutines and OS threads interact (specifically that the go scheduler can juggle goroutines between different OS threads). So, if I were using C and SDL, it wouldn't have come up. I had to fix it in the go side of the code.)

    What's the purpose of having a pointer to a type inherit an interface? What is the "thing" that is actually implementing it? You might be able to convince me that this is a good idea, but I certainly can't see why it ever would be.

    It's basically the standard value vs pointer passing as parameter, as in C.

    You're going to have to do better to convince me that no classes and no type hierarchy is a good thing without saying "watch this hour long video."

    I'm sorry, I was too tired to look for the relevant part in the video last night.

    http://www.youtube.com/watch?v=sln-gJaURzk
    51:37 - 53:25

    A part of it: "I think that's exactly what happens when you write a large piece of software. In the beginning, you think you know what's your structure, you sort of design it. It's not quite right. For the first couple of weeks, you're going to tweak it, you're going to be a good citizen and refactor and organize, and at some point you hit 20,000 lines of code or whatever, and at that point, if a bar comes up that really would require you to do a massive refactoring, you're just not going to do it, and your program is going to start to just look ugly and you're going to hack it."

    it doesn't simplify the language at all. If I want to print something, I'll type "Print" and look at the different lists of arguments that it can take, easy as pie. In your method, I have to know ahead of time the different name that matches the arguments I want to give it. Not easy.

    http://golang.org/doc/faq#overloading
    Use documentation. Programmers are supposed to know the API they're using, instead of blindly relying on autocomplete.

    I wanted to see in the docs for printf and println if it said "don't use these". It doesn't.

    http://golang.org/ref/spec#Bootstrapping
    "These functions are documented for completeness but are not guaranteed to stay in the language"

    I wouldn't depend on things that are not guaranteed to stay in the language. Use common sense in whether you should use it or not.



  • @morbiuswilters said:

    I thought the static linking just applied to object files generated by Go.

    Just tested it and apparently it's generating completely static executables. So the question is, does it statically-link libc (a wtf) or does it completely reimplement libc (a bigger wtf)?

    Either way, your go executables probably have a further impediment to running on different Linux distros, which is different kernel ABIs.



  • @paperwing said:

    If they let user code define methods on basic types, then in big codebases it would be hard to track down and maintain exactly what methods were defined on which type, because the methods would be distributed among many packages. Imagine what would happen if you want to import an 3rd party package that defines a method on int, and you already have a different method on it with the same name (and lots of code that depends on that name and interface, etc).

    This is a weak excuse. There's no confusion in a C# project which members of string were added by the .net framework and which were added by the project. Somehow, miraculously, large projects are created in C# all the time and the world does not explode. Somehow, miraculously, the compiler has the capability of saying, "whoa nelly cowpoke! You're trying to create a member function thar which already exists! Gadzooks!" (That is the actual text of the compiler error.

    @paperwing said:

    http://golang.org/doc/faq#overloading

    Use documentation. Programmers are supposed to know the API they're using, instead of blindly relying on autocomplete.

    ... because Go developers are too lazy to make Go work in IDEs with autocomplete features.



  • @paperwing said:

    if you want to ignore some returned values, use an underscore:

    a, _ = funcReturns2Things()
    

    You are literally not reading the posts you're responding to.

    @paperwing said:

    I totally forgot about these.




    So how does this help my top-level catch-all error handler+logger? Please read the posts you're responding to.

    @paperwing said:

    If none of its fields are exported, then there is no way to set the struct to an invalid state outside the package. The only case you have to handle is an empty Foo, because new(Foo) (and every other declaration/allocation) always zeroes out the variable in question.

    The zeroes are the invalid state. And having to strengthen all the methods on Foo to handle the case when Foo is uninitialized (even assuming that such a state is detectable) is pure retardation. I can't even believe you're suggesting that.

    @paperwing said:

    Some cases of those variants can be mitigated by better design: if you can handle DatabaseRow, UserInput, and File the same (or similar enough) way inside NewFoo, then simply take an interface (like io.Reader), and have one function that does the initialization.

    Yes, God knows NewFoo(databaseRow); NewFoo(file); is too complicated. Obviously I want NewFoo(NewDatabaseRowReader(databaseRow)); NewFoo(NewFileReader(file)); Yep, much cleaner now.

    That is, assuming somehow that databaseRow.GetColumn("ID") and file.ReadLine().Substring("ID: ".Length) can be extracted into a reader interface in the first place.

    @paperwing said:

    Other than that, it's true that you can't really enforce the use of NewFoo, other than documenting it.

    For a language that focuses so much on "only one way of formatting" and "bad practices are compiler errors" it sure seems to have a heavy case of schizophrenia.

    @paperwing said:

    And Println takes varargs too, by the way.

    It doesn't take a format string. Which was kinda the point of comparing it to Printf.

    @paperwing said:

    If they let user code define methods on basic types

    Literally no one in this thread suggested this.

    @paperwing said:

    Go doesn't have inheritance.

    That's exactly what's wrong with it. Its entire class of problems and kludges/language features to work around said problems would be absent if it did.

    @paperwing said:

    I meant that I had the least amount of problems with go, out of all the parts I had to work with on windows.

    Okay.

    @paperwing said:

    It's basically the standard value vs pointer passing as parameter, as in C.

    Your link has no relevance to why pointers are allowed to implement interfaces. The code in that link dereferences the pointer the first chance it gets.



  • @morbiuswilters said:

    Just tested it and apparently it's generating completely static executables. So the question is, does it statically-link libc (a wtf) or does it completely reimplement libc (a bigger wtf)?

    Why would Go use libc? That's like Oracle Java using .NET. They're unrelated things.

    @the same guy as the previous quote said:

    Either way, your go executables probably have a further impediment to running on different Linux distros, which is different kernel ABIs.

    Apart from syscalls (1 = exit, 2 = fork, 3 = read, 4 = write, 5 = open) what need is there to communicate with the kernel?



  • @blakeyrat said:

    ... because Go developers are too lazy to make Go work in IDEs with autocomplete features.

    That's blatantly unfair. Many are not lazy, but simply have a pathological fear of any technology invented after the Ford administration. And/or they are too incompetent to build IDE support.



  • @Ben L. said:

    Why would Go use libc? That's like Oracle Java using .NET. They're unrelated things.

    Even Java uses libc. See, when you have people who aren't incompetent fuck-ups designing a language that isn't a toy, they tend to try to re-use existing libraries rather than write their own from scratch. Especially when you consider the vast amount of work that libc does to allow for writing efficient, bug-free, cross-platform applications.

    So does this mean Go implements all of its own crypto routines too? Jesus Fuck Christ, that's got to be a barrel of WTFs to keep the front page fat and giggly for years. I can only imagine the gaping security holes in nearly every line of the Go SSL libraries.

    @Ben L. said:

    Apart from syscalls (1 = exit, 2 = fork, 3 = read, 4 = write, 5 = open) what need is there to communicate with the kernel?

    That's the only reason to communicate with the kernel, dipshit. However, real, non-toy languages written by people who aren't incompetent, shit-for-brains fuck-ups tend to use more advanced features offered by the kernel, instead of relying on 40 year-old APIs written for the PDP-11. But, hey, great to know Go hasn't advanced on this front, either.



  • Since paperwing doesn't seem to understand the point about Go forcing the programmer to handle errors, I'm going to just paste the following snippets comparing Java checked exceptions and Go.

    All pairs of code are equivalent from the point of view of a programmer. Java first, Go second. Apologies if the Go doesn't compile; I'm typing from memory and occasional glance at examples.

    No exceptions/errors. One return value.

    Java

    
        int GetNextNumber() {
            return 5;
        }
    
    int n = GetNextNumber();
    System.out.println(n); // Guaranteed to print 5
    

    Go

    
        func GetNextNumber() int {
            return 5
        }
    
    n := GetNextNumber()
    fmt.Println(n) // Guaranteed to print 5
    

    No exceptions/errors. No return value.

    Java

    
        int PrintNextNumber() {
            System.out.print(5);
        }
    
    PrinttNextNumber();
    System.out.println(6); // Guaranteed to print 56
    

    Go

    
        func PrintNextNumber() {
            fmt.Print(5)
        }
    
    PrinttNextNumber()
    fmt.Println(6) // Guaranteed to print 56
    

    Possible exceptions/errors. One return value. Forgot to handle the exception/error.

    Java

    
        int GetNextNumber() throws SomeCheckedException {
            if (Math.random() < 0.5)
                return 5;
            else
                throw new SomeCheckedException();
        }
    
    int n = GetNextNumber(); // Compile error. Must deal with exception!
    System.out.println(n);
    

    Go

    
        func GetNextNumber() (int, error) {
            if math.rand() < 0.5 {
                return 5, nil
            } else {
                return nil, new(SomeCheckedException)
            }
        }
    
    n := GetNextNumber() // Compile error. Must deal with error!
    fmt.Println(n)
    

    Possible exceptions/errors. One return value. Forced to handle the exception/error. The exception is serious and I decide I cannot continue. I want to propagate it upwards.

    Java

    
        int GetNextNumber() throws SomeCheckedException {
            if (Math.random() < 0.5)
                return 5;
            else
                throw new SomeCheckedException();
        }
    
    // Had to add "throws SomeCheckedException" on the signature of the method the below code is in.
    // Proves I made a conscious decision to defer the exception to my caller instead of being oblivious to the fact that an exception could occur.
    int n = GetNextNumber();
    System.out.println(n); // Will only get executed if GetNextNumber() didn't throw.
    

    Go

    
        func GetNextNumber() (int, error) {
            if math.rand() < 0.5 {
                return 5, nil
            } else {
                return nil, new(SomeCheckedException)
            }
        }
    
    if n, err := GetNextNumber(); err != nil { // Had to add ", err" . Proves I made a conscious decision to handle the exception instead of being oblivious to the fact that an exception could occur.
        return err
    }
    fmt.Println(n)
    

    Possible exceptions/errors. One return value. Forced to handle the exception/error. The exception is not serious. I can carry on.

    Java

    
        int GetNextNumber() throws SomeCheckedException {
            if (Math.random() < 0.5)
                return 5;
            else
                throw new SomeCheckedException();
        }
    
    // Had to add "catch SomeCheckedException" on the signature of the method the below code is in.
    // Proves I made a conscious decision to handle the exception instead of being oblivious to the fact that an exception could occur.
    try {
        int n = GetNextNumber();
        System.out.println(n); // Will only get executed if GetNextNumber() didn't throw.
    }
    catch (SomeCheckedException ex) {
    }
    

    Go

    
        func GetNextNumber() (int, error) {
            if math.rand() < 0.5 {
                return 5, nil
            } else {
                return nil, new(SomeCheckedException)
            }
        }
    
    if n, _ := GetNextNumber(); n != nil { // Had to add ", _" . Proves I made a conscious decision to handle the exception instead of being oblivious to the fact that an exception could occur.
        fmt.Println(n) // Will only get executed if GetNextNumber() didn't return an error.
    }
    


    Now do you get the point I've been making? Go forces you to handle errors, even if you're just going to throw them away. You cannot ignore the fact that an error might be returned.

    This is good.

    What's bad is what follows:

    Possible exceptions/errors. No return value. Forgot to handle the exception/error.

    Java

    
        void PrintNextNumber() throws SomeCheckedException {
            if (Math.random() < 0.5)
                System.out.print(5);
            else
                throw new SomeCheckedException();
        }
    
    PrintNextNumber(); // Compile error! Must handle SomeCheckedException
    System.out.println(6); // Will only print 56 after I add some code to handle SomeCheckedException, and only if PrintNextNumber() doesn't throw.
    

    But this breaks in Go.

    Go

    
        func PrintNextNumber() error {
            if math.rand() < 0.5 {
                fmt.Print(5)
                return nil
            } else {
                return new(SomeCheckedException)
            }
        }
    
    PrintNextNumber()
    fmt.Printf(6) // OOPS! This gets executed regardless of whether PrintNextNumber() actually printed 5 or not! Compiler doesn't complain that I'm ignoring the error that PrintNextNumber might return!
    



  • @morbiuswilters said:

    @Ben L. said:
    Why would Go use libc? That's like Oracle Java using .NET. They're unrelated things.

    Even Java uses libc. See, when you have people who aren't incompetent fuck-ups designing a language that isn't a toy, they tend to try to re-use existing libraries rather than write their own from scratch. Especially when you consider the vast amount of work that libc does to allow for writing efficient, bug-free, cross-platform applications.

    So does this mean Go implements all of its own crypto routines too? Jesus Fuck Christ, that's got to be a barrel of WTFs to keep the front page fat and giggly for years. I can only imagine the gaping security holes in nearly every line of the Go SSL libraries.


    What's the gaping security hole (on (nearly) each line) of, for example, this file?

    @Old-Timey Homestar Runner said:

    @Ben L. said:
    Apart from syscalls (1 = exit, 2 = fork, 3 = read, 4 = write, 5 = open) what need is there to communicate with the kernel?

    That's the only reason to communicate with the kernel, dipshit. However, real, non-toy languages written by people who aren't incompetent, shit-for-brains fuck-ups tend to use more advanced features offered by the kernel, instead of relying on 40 year-old APIs written for the PDP-11. But, hey, great to know Go hasn't advanced on this front, either.


    Oh, please do tell me what features of the Linux kernel (other than syscalls) you have used in your programs.



  • @Arnavion said:

    Since paperwing doesn't seem to understand my incoherent ramblings, I am going to post a wall of bullshit. Observe.

    It's nice how exactly zero of your go programs compile. It's adorable how you think an int can be nil.



  • @Ben L. said:

    What's the gaping security hole (on (nearly) each line) of, for example, this file?

    You want me to go through and analyze bugs in the Go crypto routines? Look, I know I'm a lot smarter than the people who worked on Go, but I don't do somebody else's job for free.

    If you have to have it explained to you why mediocre developers shouldn't be re-inventing the wheel and writing their own libraries to handle crypto concepts that they don't even understand, then you shouldn't be allowed to program. It's that fucking simple. Everybody fucks up crypto, and the only way to do it right is to use somebody else's work instead of implementing a whole new batch of mistakes.

    @Ben L. said:

    Oh, please do tell me what features of the Linux kernel (other than syscalls) you have used in your programs.

    System calls are the primary services the kernel provides (albeit no the only ones). What I was referring to, obviously, was using some of the modern system calls that were invented in the last 2 decades. But, hey, thank God we have a "systems language" that is decades behind C.

    [Deleted unnecessary vitriol.]



  • Morbs, you can't just ignore my questions. You act like a child.



  • @Ben L. said:

    What's the gaping security hole (on (nearly) each line) of, for example, this file?

    The numbers at the beginning of each line are opening the door to a GOTO injection.



    Anyways this code is so buggy, it won't even run in qbasic.exe.



  • @Ben L. said:

    Morbs, you can't just ignore my questions.

    What questions are you talking about? I'm pretty sure I answered any you had, unless you expect me to go through Go source and find bugs for you.

    Look, if you're so ignorant you don't see that re-implementing every existing library from scratch in your crappy pseudo-language is a bad idea, you shouldn't be programming. Especially if you're talking about: 1) core routines which have been pored over to eliminate security holes and give optimized performance by using whatever advantages the hardware and kernel allow; and 2) crypto libraries which shouldn't be implemented by the vast majority of programmers, especially ones who can't even understand basic shit like "how is type safety formed??"

    If you can't see that, then I look forward to seeing you on the front page in a few years, because clearly you do not understand basic software engineering.

    @Ben L. said:

    You act like a child.

    I know you are but what am I?



  • @Ben L. said:

    What's the gaping security hole (on (nearly) each line) of, for example, this file?

        37		t := uint32(c.config.time().Unix())
        38		hello.random[0] = byte(t >> 24)
        39		hello.random[1] = byte(t >> 16)
        40		hello.random[2] = byte(t >> 8)
        41		hello.random[3] = byte(t)

    I'm not a crypto programmer, but if those 'random' numbers are meant to be for security, that's pretty fucking bad.


  • Considered Harmful

    @morbiuswilters said:

    "how is type safety formed??"

    To be fair, they formed babby but then they must have used the wrong kind of scissors.


  • Considered Harmful

    @Salamander said:

    Filed under: Disclaimer: I do not know what they are used for

    Well, they're called random and they're clearly not, this is probably not a good indication.

    Hell, Sony rolled their own crypto routine and it led to the PS3 getting cracked wide open by jailbreakers. Even OpenSSL, which has millions[?] of users, had a critical problem in the CRNG that led to a massive reduction in keyspace (from an ignorant dev trying to appease valgrind, IIRC), and no one caught that one for a long time.



  • @joe.edwards said:

    Even OpenSSL, which has millions[?] of users, had a critical problem in the CRNG that led to a massive reduction in keyspace (from an ignorant dev trying to appease valgrind, IIRC), and no one caught that one for a long time.

    Technically that was just on Debian, but still, anyone who is re-inventing the wheel here is fucking up pretty badly. Fuck, TLS 1.0 itself was designed by some of the smartest non-government crypto experts in the world, but it still is full of vulnerabilities. Every SSL library has gone through several iterations of embarrassing security holes until it reached a mature state. So do the Go devs use one of these libraries and benefit from it? Fuck no, they re-invent the fucking wheel.



  • @Salamander said:

    @Ben L. said:

    What's the gaping security hole (on (nearly) each line) of, for example, this file?

        37		t := uint32(c.config.time().Unix())
        38		hello.random[0] = byte(t >> 24)
        39		hello.random[1] = byte(t >> 16)
        40		hello.random[2] = byte(t >> 8)
        41		hello.random[3] = byte(t)

    I'm not a crypto programmer, but if those 'random' numbers are meant to be for security, that's pretty fucking bad.

    Did you look at the next line? It clobbers that value with a real crypto random source.


  • @Ben L. said:

    Did you look at the next line? It clobbers that value with a real crypto random source.

    No it doesn't. It adds some random numbers after it, but it's still reduced entropy by using a Unix timestamp as a random value.



  • @Salamander said:

    @Ben L. said:

    Did you look at the next line? It clobbers that value with a real crypto random source.

    No it doesn't. It adds some random numbers after it, but it's still reduced entropy by using a Unix timestamp as a random value.

    Ah, right. Well, you can't reduce entropy by adding more data, so it should be fine.


  • @Ben L. said:

    @Salamander said:
    @Ben L. said:

    Did you look at the next line? It clobbers that value with a real crypto random source.

    No it doesn't. It adds some random numbers after it, but it's still reduced entropy by using a Unix timestamp as a random value.

    Ah, right. Well, you can't reduce entropy by adding more data, so it should be fine.

    wat


  • Considered Harmful

    Let's prepend 4 bytes of a very predictable value. It can't reduce the entropy, after all.



  • @joe.edwards said:

    Let's prepend 4 bytes of a very predictable value. It can't reduce the entropy, after all.

    Actually, the first 4 octets of random are supposed to be the Unix timestamp, so this is correct.


Log in to reply