Divided by a common syntax
owenshepherd.net
owenshepherd.net
On the other hand, C doesn't seem to attract the same type of programmers because the language itself is relatively spartan. I have a theory that simpler languages naturally encourage programmers to find simpler solutions both for themselves and the machine (thus possibly being more efficient), because more complex ones would involve more work. Asm is an extreme example, where you have to basically write every instruction the machine will execute --- and in such a scenario, even if it's mostly library calls, you're not going to want to construct and destruct a dozen objects unless you absolutely, unconditionally need to.
AbstractSingletonProxyFactoryBean
QED.
And simpler solutions for their users. Maybe a good thing; maybe not. But it's unlikely you will see a modern web browser in C.
In C, I have to maintain careful discipline in memory management. In C++, the same operators used for this in C will now sometimes do this for you, except when they don't. And so I look at C++ code and I have no idea what it's doing, and I don't know if it's safe.
In Python or whatever I needn't worry because there aren't any actual pointers or heap corruptions or segfaults.
Mind you, I have very little experience writing C++ code, so maybe I'd get used to it.
So, unsafe.
C is a car made in the days when having a safety belt wasn't even a concept, so there is no option to buckle it.
Alternatively you can take it the other route and discard RAII but then you're basically just writing C.
Some of the most heinous, insane bugs I have ever seen are because C++ is a complexity nightmare and very intelligent people struggle to get things right. Rust is orders of magnitude safer as it forces you to play with safe constructs only (avoiding surprises left by others, or past you) and wrapping anything explicitly unsafe.
[1] https://blogs.msdn.microsoft.com/vcblog/2016/03/31/c-core-gu...
[2] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus
But its insistence on $GOPATH is infuriating.
I have many, many projects in dozens of languages, organised in a way that reflects both my development and deployment practices.
But Go wants to be different. And it wants to be separate.
It's a tiny knitpick, and there is much I like about Go, even the way it handles exceptions. But it inconveniences me. And so, I guess I'll pout.
If you have a ProjectX with the path $pathx, set $GOTPATH to $pathx and place your source files in $pathx/src/projectx
I also hate that I have to do this though and I totally understand what you mean. Just wanted to mention my favorite work-around to see if I get some feedback on it being stupid/clever/ordinary.
$(CC) $(FILES) -L$(LIBS) -o $(EXE)
Allows me to change and modify on a per project basis how to compile a program. In fact, it allows me to change exactly how it's compiled or cross-compiled.I can use system libs if available, and if not, drag down the latest, build that locally, and link locally.
Go isn't as flexible. It's opinionated.
There doesn't seem to be any benefit other than standards compliance in having a GOPATH.
I have to circumvent how Go wants to work so that it can fit with the standards I have that C, C++, C#, F#, Haskell, D, Nim, Red, Chicken, Python all work with without being bashed into submission, they supply tools to make it easier.
They don't have lead developers standing up and saying "All Python libraries should be developed in this particular folder structure. Even if it makes integrating C code more difficult."
That feels... Wrong.
So repeatedly setting GOPATH sucks, and can cause havoc if the envar isn't released properly by, say, a failing build.
But, as I said to start with: This is a tiny knitpick.
It means I come back and try Go, time and again.
It also means I spend more time wrestling Go into submission within my automated testing and deployment structures, than writing code in it.
You can also write your own wrapper script around Go build tools. Or even bypass `go build` entirely and call the Go compiler in the exact same way you'd described above (-o and -L flags included). Run `go build -n` against your project to see what `go build` does (it's print only mode, no compiling will happen) and you'll see it's really no different to what you were asking for
So everything you want to do can and is supported by Go. It's just not it's default behaviour so you needed to do a little digging to find it.
Personally though, I find the inconvenience of having to change GOPATH / GOOS / GOARCH to be significantly less annoying than having to write makefiles and configure scripts to handle every platform I might want to target. For most people `go build` abstracts away the pain of cross compiling and build scripts quite nicely. In fact that was one of the biggest reasons I started using Go in the first place (I wanted something I could rapidly code and compile on AMD64 then rsync onto ARM devices back when I was experimenting with building custom embedded devices for my car).
edit: just want to add that I'm not under any illusion that Go nor it's tooling is perfect. I'm just saying Go can easily support your specific workflow preferences even though superficially it appears otherwise.
I would love some documentation on it. The Go developers hostility to the approach is hugely offputting.
If you don't mind me saying, maybe some of the hostility is because you keep saying Go "cannot" do x, y or z without looking at said documentation first? I know I've gotten terse responses from the community in the past when I've asked questions that were already well explained in the docs. I agree it's not nice being on the receiving end of such responses but I can also sympathise with why the community get sick of answering basic questions that are already available in a simple Google / DuckDuckGo search.
> 1) ... The $GOPATH provides us with a place to store common, shared third party libs on our system, and our own projects.
> #1 is the correct and supported way. The other methods are actively discouraged. Andrew.
But, for example, the documentation for GOPATH makes no suggestion it is even possible [1]:
> GOPATH must be set to get, build and install packages outside the standard Go tree.
> Each directory listed in GOPATH must have a prescribed structure:
And the compiler help says:
> Build adheres to certain conventions such as those described by 'go help gopath'.
It's exciting that I've been mislead about the ease of this, but I wouldn't say it is well explained in the docs.
The team want one true way of building a go pkg.
[0] https://groups.google.com/forum/#!topic/golang-nuts/dxOFYPpJ...
[1] https://golang.org/cmd/go/#hdr-GOPATH_environment_variable
> But, for example, the documentation for GOPATH makes no suggestion it is even possible [1]
Well to be fair you were looking for information about compiler flags in the documentation for the envvars; which perhaps wasn't the best systematic approach to research your problem? But hopefully you now have the information you need? Or at least better idea of how to find the answers you seek?
>The team want one true way of building a go pkg.
This is very true. However as long as your code follows the same standards it doesn't really matter how you chose to organise your source files as it should still compile on other people's systems using `go build` in the idiomatic way. And for what it's worth, a lot of people don't follow the directory hierarchy in the strictest way and/or use `go build/install`; choosing instead to use their preferred vendoring system. So I doubt many people would have a problem if you wanted to do your own thing just so long as the code is still compatible with Go's standard build tools should you release your projects to the world.
I understand that different people find themselves preferring different programming languages based on their syntax, features, tooling, etc. But I do think it would be a shame not to use a language you conceptually like just because of a single and easily changeable environmental variable.
Am I wrong in my understanding?
That's a bit of an exaggeration, at worst -- yes, C is a bit more high-level than a typical assembly language, but most C constructs can be mapped to a typical processor's assembly language in an obvious way, something that isn't true of any other language I know of.
I don't know much about the PDP-11, the machine for which C was originally designed, but for modern processors this "obvious" mapping is typically not how things are done in assembly. To give an example:
int x = 42;
x = x+1;
foo(&x);
The way how it was originally conceived in C was that we reserve, say, 4 bytes on the stack and pass the adress of x on the stack to foo. On the other hand, any assembler programmer would try to store integer variables in a processor register (where we can't take an adress) and synchronize it with the x on the stack before we pass x's adress to foo. In other words: x now is now "two variables": 4 bytes on the stack and a register, which are synced if necessary.Summarizing: In assembly we have "two kinds of local variables":
- Registers [one cannot take adress of it]
- Adresses in stack frame [on RISC cores (load-store architecture) these can only be accesses by an explicit load/store and must be loaded into register before anything useful can be done with them; on x86-32/x86-64 the story is a little more complicated - I don't want to go into the details here]
As I have shown these two completely different concepts are intertwined in C into the conept of local variables. I hope this convinces you how the concepts in C don't map directly to modern assembly code (i.e. a direct mapping yields bad assembly code).
Ironically C has the concept of "register" variables, of which one cannot take the adress. This feature is hardly used in modern C, but maps IMHO much better to the "register" concept in assembly (but I'm not a C expert).
- Strict aliasing rules (most important reason why C should not be considered as "portable assembler")
- Overflow for adding/subtracting signed numbers is undefined behavior
- Implicit casting of integer types in expressions; OK, there are rules for this, but under assembly you have all this under direct control without having to learn lots of arcane rules
- There are things that can easily be done in assmbly that cannot/can hardly be done in C (for example taking adress of a label (very useful for implementing coroutines) is only an GCC extension but not standard C: http://stackoverflow.com/q/1777990/497193). Or how do you control the amount of stack space that a function is allowed to use (would be very useful for embedded applications where you strictly want to avoid stack overflow and you want to allocate exactly as much stack space as necessary, but not more)
As though compilers aren't themselves written by humans.
When abstractions move into the language itself, it's harder to observe what's going on when they do something strange (even if it's correct) than if they were just some other library code in the same program.
When I write C++ the language magic is "just another library". If I'm uncomfortable I just step through those magic layers in a debugger and I'm then happy, just like a C library user would step through compiled-from-source third party stuff.
"But a C coder can read the third-party code!" But a C program already hides the magic of function calls and stack frames ... C++ is just a few more layers of abstractions just like that one!
The difference is: For a library you can (in principle) write your own implementation and replace the given one by it. Or even remove the library completely if it seems a good idea. For language features this is not possible (without writing a new compiler that implements something different than C/C++). Thus the language features of C++ clearly cannot be compared to a library - they change the language (if left away), while a library is no different language, but a text written in the language.
In principle yes, but there are good and bad abstractions (bitshifts that print probably being in the latter category), and facilities that break important symmetries of their surrounding code (exceptions).
Slightly less tongue-in-cheek, what sort of symmetries are broken by exceptions?
They make it much harder to maintain single entry/exit in functions where you want that - and, crucially, harder to notice when a function isn't single entry/exit. They also violate referential transparency, which means e.g. caching the result of a repeated function call is no longer necessarily safe.
Not seeing this one. Unpredictable exception-throwing only happens if the work being done by your function isn't pure, i.e. it depends on something other than the function parameters. And if that's the case then caching its result is a bad idea anyway.
What am I missing here?
This isn't true. The canonical example is trying to grab the first element of an empty list. You either check and catch the error or eat the exceptional behavior, but some pure functions are just partial and aren't defined for all inputs.
(Whether or not they throw a catch-able exception depends on language/implementation and is really not relevant to my point.)
This comes up a lot in the Haskell community -- code outside IO is guaranteed by the compiler to be pure, but you can still get hit with an asynchronous exception because you called a partial function.
Don't use exceptions. Not supported.
Theoretical C++ has tons of stuff. Practical C++ doesn't use most of them :D
Exceptions have been quite well supported by all major compilers on all major platforms for a very long time.
And that is really puzzling me. Why do tutorials (from 20 years ago) starts with "cout << hello world;" ???
> Exceptions have been quite well supported by all major compilers on all major platforms for a very long time.
Try throwing exceptions in the kernel or in a driver, see how well it goes, or try in an embedded device. (That is, when it can be done in C++, and not C only).
I remember back in 98 when first picking up Java, thinking, WHAT NO MACROS?, but now i believe that was an incredibly good idea not having them. Of course Java now has things like aspects, et. al, so you never can get away from things if you really want them.
The only thing to know about C and C++. Don't use any of them unless there is no choice.