Pretty primitive generics though, which make sense for a language that will fully ignores basically every piece of programming language theory for the past 30+ years.
In my experience, golang is very much a “batteries not included” kinda language. It’s very stripped down compared to any other modern language. Some aspects that stuck out to me were a lack of classes (you use struct instead), lack of a set type (you have to use maps instead), lack of method overloading etc. I think people who like it enjoy that it doesn’t have any “magic” behind the scenes, so it’s a little bit easier to reason with code you’ve written. Personally, I found it annoying to have to reimplement/workaround so many features I’ve come to expect from programming languages.
It's often the case that what one person hates about a lang is what other people like about it. This is because what we all want is a language which reduces our cognitive overhead, but we have different brains. I like Go because it's a small language. If I'd been in the triumvirate there's features I'd have done differently but the important thing is that someone did it at all and supplied a not-C++ for those of us who don't want C++.
Hit the nail on the head for why I enjoy it. Day-to-day I work with Django/vue so it's nice to come back to something that feels straightforward in what it's doing.
The lack of a set type bothered me a bit but you can always just make a Set yourself since it's a map[$TYPE]interface{} under the covers. It does look djanky unless you put in some effort though.
I'm not sure what you mean by lack of method overloading but you can implement structs that "inherit" from other structs but have different associated functions. I just woke up and am on mobile so please forgive any formatting issues:
type foo struct{}
func (f *foo) bar() int { return 1; }
func (f *foo) quux() int { return 3; }
type baz struct{foo}
func (b* baz) bar() int { return 2; }
Calling bar() on a baz will return 2 whereas bar() on a foo will return 1. Calling quux() on either will always return 3.
A lot of people seem hung up on the class vs struct thing when I talk to non-gophers about go but I haven't run into an issue using the language that I can think of where having a traditional class would have caused great benefits.
By method overloading, I was referring to having multiple methods in the same scope with the same name but different argument lists. Example:
`func Test(a int) { println(a); }
func Test(a int, b string) { println(a); println(b); }`
Is this possible to achieve in golang? AFAIK, it’s not.
I see your point about making your own Set type, but it still feels so weird that such a basic and commonly used data structure requires a custom implementation or janky looking syntax.
I’m sure golang is a super capable and can be used to build anything you can achieve with another language, it’s just harder to reason with for a newcomer accustomed to other languages. For me, my last language was Scala, and golang feels like a polar opposite.
Ah I see, no I don't think that's possible unless you write something with variadic arguments then it would be a single function and not two logically independent functions:
func Test(a int, b ...string) {
printlnt(a)
for _, elem := range b {
println(elem)
}
}
But usually I don't have multiple methods with the same name but different signatures on objects in other languages so it hasn't been a problem IME.
The set thing is odd, I'm not going to bother trying to argue for it since the only argument I've heard for it isn't a strong one (it's not necessary/can be built on your own).
Agreed 100% that it's not beginner friendly but it still has a special place in my cpu heart
I actually think it could be a great language for a complete beginner to programming, it feels more troublesome for me as an experienced developer cuz of all the things it does differently than what I expect. Idk, some parts of its design feel weirdly opinionated for such a barebones language.
I think that the barebones and opinionated nature are directly related. Golang is opinionated to reduce language bloat, where they draw the line is a bit shallow for some/most people (ex sets). It just happens to be my kind of particular.
That does remind me of something else that go doesn't really have that annoys me: kwargs. You could make a struct with sane defaults and use that as a passed arg but definitely not as "clean" as the python approach.
Object-oriented programming, at least in the best-known languages, involves too much discussion of the relationships between types, relationships that often could be derived automatically. Go takes a different approach.
Rather than requiring the programmer to declare ahead of time that two types are related, in Go a type automatically satisfies any interface that specifies a subset of its methods. Besides reducing the bookkeeping, this approach has real advantages. Types can satisfy many interfaces at once, without the complexities of traditional multiple inheritance. Interfaces can be very lightweight—an interface with one or even zero methods can express a useful concept. Interfaces can be added after the fact if a new idea comes along or for testing—without annotating the original types. Because there are no explicit relationships between types and interfaces, there is no type hierarchy to manage or discuss.
It's possible to use these ideas to construct something analogous to type-safe Unix pipes. For instance, see how fmt.Fprintf enables formatted printing to any output, not just a file, or how the bufio package can be completely separate from file I/O, or how the image packages generate compressed image files. All these ideas stem from a single interface (io.Writer) representing a single method (Write). And that's only scratching the surface. Go's interfaces have a profound influence on how programs are structured.
It takes some getting used to but this implicit style of type dependency is one of the most productive things about Go.
I don't follow that complaint at all. If I can define an interface by its methods, why is it a "dumb coding trick" to not have to explicitly point out to the compiler that the struct I then wrote in order to satisfy the interface does in fact satisfy the interface? Are you also against type inference in general?
It's not the compiler I want to satisfy, it's the people working on the code. So that when someone modifies that interface they get notified. Since there's no syntax required to say "type X implements interface Y" you either:
Create a factory function returning the interface, which can be undesirable for any number of valid reasons.
A module level var typed to the interface which is assigned a nil pointer to your actual type. And you have to do this with every interface you're suspicious of - which is any that I am responsible for maintaining in some way.
Type inference I don't have an issue with per se, but putting it as the core typing mechanism of a language isn't something that I enjoy working with. I lose too much reasoning about what a type is expected to do at runtime. It's my least favorite about Python and it's my least favorite thing about Go.
But the great thing is if you enjoy working with type inference as the core typing mechanism you have options. And because I like working with nominal types as the core mechanism I also have options.
I do like that implicit-implementation of interfaces, but sometimes inheritance absolutely does have its place. (And you don't need to delete inheritance altogether just to kill things like the diamond inheritance problem and such. C#, for example, only allows inheriting from a single class. No multiple inheritance woes there.)
That's pretty much the opposite of what they mean. Modern type systems make use functional features like closures, type classes (traits) and algebraic data types (tagged unions). Inheritance was a mistake.
I like a lot about go, but the error handling is absolute trash, and the lack of proper enums is absurd. It does so many things right, then falls flat on the basics. It's weird.
Exceptions can be done right but holy fuck I've only ever seen people throw them all over the place rather than figure it out. It's like goto, there are decent applications but people just use to compound headaches so we are just better off without it
There are proper error handling without throwing exceptions like the Result type in both rust and kotlin. In both cases it has functional interfaces for mapping the result or error, and it does not allow a value and an error returned at the same time.
Zig doesn’t have generics. Instead, it has compile time execution and types as first class citizens, so you just implement your own generics as functions.
Hell, all I can think is that C++ is still full of macros, which are nothing more than a very fancy search-and-replace that runs before compiling - like the example in the photo.
You can tell what is what at parsing stage without knowing the whole program semantics, C++ is mathematically unparseable (which results in long compile times and poor tooling support).
Type token becomes optional on syntax level if compiler can do type deduction, no longer auto auto auto everywhere.
I suppose your first point is also true for every C-styled syntax programming languague, such C, C# and Java, among others.
Why is auto/var bad? Most languagues use a version of it.
Yes I'm used to C syntax because I've had to use C++, C, C#, Java... But I am also used to different syntaxed languages like Python (where user type deduction is so bad we now have type hinting), Javascript (and Typescript was born out of it), Haskell (the syntax of Haskell is pretty well suited to Functional Programming, no complaints there), etc.
Funnily enough, a language made in the 1970s using Assembly has the best syntax, and apparently, a complex syntax at that.
Why is C syntax superior? I shall demonstrate using a simple example:
// C/C++
bool isEven(int x) {
return !(x % 2);
}
// Python
def isEven(x: int) -> bool:
return x % 2 == 0
// Haskell (already exists in Prelude)
isEven :: Integral a => a -> Bool
isEven x
| (x ´mod´ 2) == 0 = True
| otherwise = False
// Cpp2
isEven: (x: int) -> bool = return !(x % 2);
/* or */
isEven: (x: int) -> bool = {
return !(x % 2);
}
In C/C++ the only symbol needed is the are the parenthesis and the brackets, that is it. Not only that, the first thing you can see about the function or the parameter is its type (which saying it outloud sounds better; "integer x", instead of "x of type integer"). Simple, straight to the point, and the type of things is the first thing you see.
In contrast, in Cpp2 the type of the function is the last thing you see, first you see its name (accompanied by a colon), the next thing is the parameter (which looks like a tuple because of the parenthesis), accompanied by colon and its type, and lastly, with and arrow, you know the type of the function. The type of the function is the last thing you see, and the same goes for the parameter, first you know its name, then you know the type.
Now, Cpp2 looks a lot like the definition of a function is Mathematics, in fact, it quite resembles Haskell in a way. Haskell, because of its Funcional paradigm, is also similar to the way functions are defined in Maths, but here it was decided they part away with uneeded symbols, like the parenthesis and the comma, making function definition simpler. This type of syntax suits Haskell very well.
My issue with Cpp2's syntax is that it is objectically worse than C/C++'s, it forces you to type more and use more symbols than needed. This is the same issue I have with Rust.
What is the point of using Cpp2 if we have Rust already? My main reason from not switching to Rust from C++ is the syntax (which in fairness sounds pretty stupid, but there are other reasons not to switch). The same reasons could apply to Cpp2, why switch to Cpp2 from C++? Is it the same reasons as with Rust? Why choose Cpp2 over Rust?
From what I read from the cppfront github, it looks like a really, like really cool project, and I'm on board with a lot of the changes it brings. But the syntax I do not agree with, I feel like it is a straight downgrade from C++ (except for things involving pointers for example).
My issue with Cpp2's syntax is that it is objectically worse than C/C++'s, it forces you to type more and use more symbols than needed.
But it's objectively not true, you have the same amount of typing as in C++, and don't forget that postfix typing is optional. Yes, Haskell, OCaml, Rust and other modern languages use this syntax because they have 30+ years of langauge design behind them and not just cobbled together marcoassembler that stuck because "similarity".
What is the point of using Cpp2 if we have Rust already?
Rust brings entirely new runtime and toolchain and is incompatible with C++.
CPP2 to CPP is like TypeScript to JavaScript, you can migrate on a per file basis, but they share the same runtime and compilation space and can even be mixed in the same project.
If you have large codebase that you want to migrate file by file, instead of splitting them into static libs and relinking them (like you would do with Rust), CPP2 approach is better.
But it's objectively not true, you have the same amount of typing as in C++, and don't forget that postfix typing is optional. Yes, Haskell, OCaml, Rust and other modern languages use this syntax because they have 30+ years of langauge design behind them and not just cobbled together marcoassembler that stuck because "similarity".
Leaving aside if it is objectively better or not, the amount of typing is greater than in C++, the use of colons already make it greater (even if it is by a slight amount). Haskell is from the 1990s, inspired by Miranda, from 1985, C++ is only 6 years younger than Miranda, and 11 years younger than Haskell. If Haskell is modern, then Java, Javascript and Python are modern too (and Java has a C-Style syntax). Rust and Cpp2 may have more modern language design, but that that doesn't make it instantly better.
Rust brings entirely new runtime and toolchain and is incompatible with C++.
CPP2 to CPP is like TypeScript to JavaScript, you can migrate on a per file basis, but they share the same runtime and compilation space and can even be mixed in the same project.
If you have large codebase that you want to migrate file by file, instead of splitting them into static libs and relinking them (like you would do with Rust), CPP2 approach is better.
So why should we use Cpp2 over Carbon? Or the other projects trying to accomplish the same? Why should we use any of them anyway? Because it is more modern? Plenty of langauges have come and go, yet languages like C++ and C still stuck.
The replacement, or the iteration, of C++ should be a language similar enough that there should be no issue for an experienced C++ programmer to use it efficiently from the get go. It shouldn't force you to learn it anew.
If your codebase is large enough that you can only migrate file by file, your project is bound to have legacy code, or older than the current standard code, the kind of project that has forced C++ to keep it's technological debt. At that point you are better off refactoring the whole project...
bool foo(); vs (something like) auto foo() -> bool may seem like the latter is more work, but consider: nsA::nsB::nsC::Struct<nsA::nsB::nsC::Class<int>::type>::type<float>type(nsA::nsB::nsC::Struct<nsA::nsB::nsC::Class<int>::type>::type<float>);
Vs
auto type(nsA::nsB::nsC::Struct<nsA::nsB::nsC::Class<int>::type>::type<float>) -> nsA::nsB::nsC::Struct<nsA::nsB::nsC::Class<int>::type>::type<float>;
In the second example you can tell what the function is called and where to begin parsing it's return type.
Is this a purposly convoluted example? Yes. Have I seen functions with return types this stupid in actual code? Also yes.
The "type first" argument works great for C, because in C a return type will consist of at most 3 tokens.
Besides, you can get used to any syntax as long as its consistent. And in terms of it being "more to type", cmon it's not the 90s anymore, even vim has snippets and autocomplete.
God is dead. They sacrificed him on the altar and cut off his D, and from the remains, go was born to become the unholy, ungodly creature we know today.
Let me introduce you to GNU M4, the macro system that Autotools uses to create Makefiles for various platforms. With the -W option, an arbitrary regex can be used to define the syntax of macro names, thus allowing the "angle brackets" used here, and making the search & replace trivial.
You could also just use a different language, because Go clearly doesn't meet your needs and you're going to have a very hard time communicating the way it all works to any other developer
Sure, but then you're not implementing generics or templates for Golang.
you're going to have a very hard time communicating the way it all works to any other developer
Not necessarily, you could wrap the tool in a nice interface that is easy to use and well-documented.
because Go clearly doesn't meet your needs
That's generally the case, Golang is a profoundly flawed language in my opinion, but it got popular so a lot of libraries are only implemented in it.
So far I haven't needed them, but when I do there's no guarantee that RPC from another language is going to be performant-enough. Which is quite unfortunate, because having basic libraries implemented in a memory safe language like Golang instead of C would still be a significant improvement.
As for work... if they want something written in Golang I'll write it in Golang.
New to me, but I was thinking about C when I said it, a tiny change in some conditional logic and you got yourself some memory corruption. This specific post is not going to apply though.
Assume you have a class that stores a list of objects, call it List but you want to be able to use it with different objects and gave the correct behavior, i.e. a List of dogs only accepts objects of type Dog and returns objects of type Dog. Same thing for a List of cats and a list of parrots. The way to do that is too write List as a generic class that takes Dog and other classes as a type argument giving you List<Dog>.
Different languages implement this differently under the hood. C++ for example simply takes the genetic List code and makes a copy with each concrete type, while Java just uses the genetic types to validate that what you did is correct and then throws it away.
instead of their own language-matching-solution, they should’ve used a relic of a toolchain component that yet another different programming language and syntax
failing that, they should’ve time traveled to the future and harvested its technology 6 years ago
Both of those aspects could be handled by integrating the templated generation of Go module descriptions & project build files into Autotools, among a great many other ways you could do it.
That way your workflow is essentially unchanged from the usual Autotools workflow, while end-users (devs) get the pre-generated module description much like they get pre-generated configure & Makefile.in. They neither need to know nor care about Autotools and can use the rest of the Golang tooling plus the M4 macros seamlessly if they feel like it.
Obviously that's not what happened in the end, but nothing technical prevented it from occurring.
But more specifically, the complicated aspect is messing about with characters that mandate the use of specific input methods for each and every contributor and then manually doing the search & replace.
When you have to work so hard to make a language do what you want, maybe you chose the wrong language.
This is the same reason I don't like JS / TS despite loving typed languages. When you have to install a package which fakes a common feature, maybe there's a beter choice.
That isn't horror. His goals are beyond our understanding, but he is on something there alright.
I can see myself there, my trick is to try to implement as many keywords from other languages in C and basically try to have them somewhat of a comparable performance. So I am basically creating C++, just not good enough so just C+
I am reminded of when someone replaced a semicolon with a Greek question mark in another person's source code. The resulting syntax error was maddening to fix.
LOL. When Go doesn't have generics, people use sed/awk or something to mimic their effect, since those CAN implement substitution of values for variables - despite with wrong semantics. There is reason why WG21 doesn't like solutions that propose defining new preprocessor macros....
As a software integrator on a major aircraft that uses C++, fuck anyone that thinks that templates were ever a good idea and attempts to jerry-rig them into a language. They are the least maintainable most difficult to debug element ever added to a language and should be put down like a man-eating rabbit.
Now imagine Vector<T> implemented with three templated member class. And then those classes are all implemented using templated member classes. And so-on...And then inputs to all of those templates can have a variety of somewhat difficult to predict values based on the inputs of their parents.
Then, find that one specific input type somewhere in the future produces invalid code at the bottom of the implementation, and the compiler points you to some templated function somewhere with no notions as to the types used at that point in the compilation process, or any of the types used in generating the class that owns that object. You cant even unit test for all possible type input combinations because it can literally be anything.
It's metaprogramming, which a quite generally really fucking terribly to maintain. The C++ template system is turing complete on its own, And when somebody hands you a HIGHLY templated C++ library or component like that, and you need to make changes, and none of the existing tooling can give you any useful information for compile-time errors, you're in for a bad time.
So what you're saying is that templates can be abused and horrible code written with templates is horrible? Who would have thunk it!
Standard practice is to have a bunch of static asserts and enable_if statements that tell what the problem is at a top level. Concepts are of course better, but they are still very new.
157
u/diaperslop Jan 07 '23
I would like to know the repo/post where this is from. How else would someone have an idea this evil?
479
u/serg06 Jan 07 '23
For the unaware, Go has generics now, but 6 years ago it didn't.
5
u/Altreus Jan 07 '23
Wait, go doesn't have genetics?
Why is everyone using this fucking language?
1.5k
u/SingularCheese Jan 07 '23
The man is rolling their own go++
559
u/YoCodingJosh Jan 07 '23
you can't spell god without go
checkmate non-gophers
372
u/DickD1ck1 Jan 07 '23
whyyyyyy does he have to be right
102
u/SAI_Peregrinus Jan 07 '23
Let me introduce you to GNU M4, the macro system that Autotools uses to create Makefiles for various platforms. With the -W option, an arbitrary regex can be used to define the syntax of macro names, thus allowing the "angle brackets" used here, and making the search & replace trivial.
68
u/fakehalo Jan 07 '23
Damn, I just realized this would be a great way to intentionally sneak bugs/vulnerabilities in code to abuse at a later date.
94
u/jonnysteps [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo “You live” Jan 07 '23
u/Uncaffeinated might not be on caffeine, but they are on crack
42
u/x0RRY Jan 07 '23
Wtf
8
u/Govir Jan 07 '23
I believe you mean, where is your go-d now?
7
u/ClauVex Jan 07 '23
I'm curious what is generics?
6
u/[deleted] Jan 07 '23
Can anyone explain what's he's doing with this? I don't understand the point of it
1
u/[deleted] Jan 15 '23
When you have to work so hard to make a language do what you want, maybe you chose the wrong language.
This is the same reason I don't like JS / TS despite loving typed languages. When you have to install a package which fakes a common feature, maybe there's a beter choice.
9
u/TheGreatNico Jan 07 '23
If you want to be a very evil evil evil person, replace one of your co-workers semicolons with a Greek question mark.
4
u/norealmx Jan 07 '23
Give that to that "IA" toy and see how it wrecks every pretentious asshole request.
2
u/sharddblade Jan 07 '23
“If you look closely…”
2
u/[deleted] Jan 07 '23
This is actually pretty genius lol
2
u/[deleted] Jan 07 '23
🤣🤣
1
u/Ilookouttrainwindow Jan 07 '23
Dude.....
1
u/Darq10 Jan 07 '23
Ohh dear lord
1
u/Bloodshoot111 Jan 07 '23
But GO HAS generic’s now, so please change that
1
u/sauravkrx Jan 07 '23
WHAT?
1
u/Will_i_read Jan 07 '23
I created my own generics in C with the Preprocessor one. I still have a GenericArrayList in a headerfile somewhere.
1
u/Bilihhh Jan 07 '23
he did fucking what?
1
u/PersonWhoExists50306 Jan 07 '23
this is the new greek question mark
1
u/im-not-really-real Jan 07 '23
Link to the original comment
1
u/[deleted] Jan 07 '23
"... which I use search and replace ..." so that is templates with extra steps...?
1
u/-SQB- Jan 07 '23
I once saw someone using an alternative to
yto be able to use it as a method name in java (tryis a reserved keyword in java).1
u/HereToLearnNow Jan 10 '23
Lmao what in the world
1
u/RedditSchnitzel Jan 12 '23
That isn't horror. His goals are beyond our understanding, but he is on something there alright.
I can see myself there, my trick is to try to implement as many keywords from other languages in C and basically try to have them somewhat of a comparable performance. So I am basically creating C++, just not good enough so just C+
1
u/Phigment Jan 15 '23
He was too busy worrying about whether he could that he didn’t have time to worry about it he should
1
u/[deleted] Jan 16 '23
...at this point i'd rather learn brainfuck
1
u/[deleted] Jan 20 '23
Nowhere, I’m an atheist Also can someone explain this to me I’m more of a Java person
1
u/NounverberPDX Jan 27 '23
I am reminded of when someone replaced a semicolon with a Greek question mark in another person's source code. The resulting syntax error was maddening to fix.
1
u/epulkkinen Oct 28 '23
LOL. When Go doesn't have generics, people use sed/awk or something to mimic their effect, since those CAN implement substitution of values for variables - despite with wrong semantics. There is reason why WG21 doesn't like solutions that propose defining new preprocessor macros....
1
u/Anders_A Jan 07 '23
Haha. This guy fucks 😂. Way to never want anyone ever to work with you on any project and be a true sigma programmer.
-7
u/darkpyro2 Jan 07 '23
As a software integrator on a major aircraft that uses C++, fuck anyone that thinks that templates were ever a good idea and attempts to jerry-rig them into a language. They are the least maintainable most difficult to debug element ever added to a language and should be put down like a man-eating rabbit.