dpryden
Joined 6 years ago
Joined 6 years ago
It says:
> I give the following general definitions for strong and weak typing, at least when used as absolutes:
> Strong typing: A type system that I like and feel comfortable with
> Weak typing: A type system that worries me, or makes me feel uncomfortable
It did make me go pick up an old copy of PC Magazine from 1995 from the other side of the room and start leafing through it, though.
In any case, though, my understanding is that the technical capacity for this has existed for nearly 10 years now, just behind a configuration setting. So it's possible that this change is just a code cleanup. It's also possible that someone is trying to increase the percentage of searches that have location information, that doesn't seem terribly far-fetched either, and I can imagine lots of ways people could try to rationalize it as actually benefiting users. (Whether it actually does benefit users is of course debatable.)
The first edition of K&R was published in 1978.
Wikipedia says that OS/360 had a notion of threads as early as 1967, although the distinction between threads and processes wasn't as clearly defined at that time.
In 1978, threading and concurrency was still an area of academic research. There are some great papers from Dijkstra and Lamport from that era, but much of the research at that time considered each concurrent "thread" to be a separate program; that is, each process was conceptually single-threaded, and if you wanted to do multiple things you made multiple processes for them.
The idea of multiple mini-processes inside a single process came later and took a while to stabilize into its modern form. POSIX didn't standardize thread-related APIs until 1995 and Linux didn't get modern POSIX threads support until Linux 2.6 in 2003.
I'm not saying that GC is always the best choice, but this article gets the most important argument wrong:
> 1. Updating reference counts is quite expensive. > > No, it isn't. It's an atomic increment, perhaps with overflow checks for small integer widths. This is about as minimal as you can get short of nothing at all.
Yes, it is. Even an atomic increment is a write to memory. That is not "about as minimal as you can get short of nothing at all".
Additionally, every modern GC does generational collection, so for the vast majority of objects, the GC literally does "nothing at all". No matter how little work it does, a RC solution has to do O(garbage) work, while a copying GC can do O(not garbage) work.
Now, that's not to say that GC is automatically better. There are trade-offs here. It depends on the workload, the amount of garbage being created, and the ratio of read to write operations.
The article says:
> I've already stated I'm not going to do benchmarks. I am aware of two orgs who've already run extensive and far-reaching experiments on this: Apple, for use in their mobile phones, and the Python project.
I can counterpoint that anecdata: Google extensively uses Java in high-performance systems, and invented a new GC-only language (Go) as a replacement for (their uses of) Python.
The right answer is to do benchmarks. Or even better yet, don't worry about this and just write your code! Outside of a vanishingly small number of specialized use cases, by the time GC vs RC becomes relevant in any meaningful way to your performance, you've already succeeded, and now you're dealing with scaling effects.
That said, I think I tend to use "upstream" in a similar sense to how package maintainers talk about packages: "upstream" is the source (where the thing originally came from) and "downstream" is the sink (where I will send it to). This implies that "upstream" for a request is "downstream" for a response, and vice versa. I don't know if that's necessarily correct usage, but that's how I've done it.
Knowing how to write a topological sort isn't the key skill here (although, I would argue, it's a good skill to know, and it's probably much simpler than you're imagining). The key skill is knowing that a topological sort will solve the problem, or perhaps it's simply knowing that "finding an order of actions that satisfies these dependency constraints" is called a topological sort.
I have always been under the impression that the goal of leetcode-style interviewing was actually to measure a candidate's ability to recognize what algorithmic tool to use, rather than to measure a candidate's ability to implement an algorithm from scratch. When I've been in the position of interviewing in the past, I've always been more interested in that problem-solving approach than in the actual code.
In my experience, most software jobs are 90% figuring out the problem that needs to be solved and coming up with tactics for solving the problem, and 10% actually implementing those tactics. In that context, investigating the ability of a candidate to analyze problems seems like an excellent interview technique.
To me it seems similar to how "auto" as a noun is generally short for "automobile", but most people are aware that other things can also be called "auto". When a camera says it is "auto focus" I cannot imagine that any normal person would assume that phrase has anything to do with automobiles.
It is incredibly common for the same word to have different meanings in different contexts. I personally have literally never had a conversation about cryptocurrency in which any person used the word "crypto" to mean "cryptocurrency", so I am clearly out of this loop. But if people decide to use it that way as slang in a certain context it certainly doesn't change the meaning of related words, or even mean it's impossible to use a different slang meaning in different contexts.
As an example: imagine I am developing my application locally, at http://localhost:8080/ , and this application supports an OpenID Connect identity flow with an identity provider, https://idp.corp.example . Today I can test the login flow by telling the IDP that localhost:8080 is a valid URL to redirect back to, so that I can click a "login" button in my application, log into the real IDP, and get a token posted back to something like http://localhost:8080/idp-callback . This makes it easy to develop a system locally that also communicates with various backend microservices which require authentication with a common IDP.
I can't imagine that this is a rare scenario: it seems pretty normal to me. But if I understand the proposal, it sounds like the long-term goal is to prevent this kind of environment for local development, and instead force you to either run your dev stack remotely (with a public IP!) or else run your entire IDP stack locally (so that it has a local IP). Neither of those seem like good ideas to me.
Of course, the other option would be to modify local dev servers to accept CORS preflight requests and respond correctly, but I'm always slightly uncomfortable adding code into a local dev stack that would be unsafe if enabled in production. At very least it makes it harder to debug when something inevitably goes wrong with this API flow.
There are probably ways to solve this by introducing more proxies into a local dev stack, but I worry that these kinds of little papercuts will just make development that much harder for microservices-architecture applications, which are already hard enough to develop and debug as it is.
In either case, though, it's an inside joke precisely because it's more relatable to those who are (or were) inside. In particular, I think it would be most funny to someone who was at Google about a decade ago; when I left Google in 2017 things had already changed enough that this didn't ring quite as true for new hires.
That said, GCP is not very representative of what the internal platform looked like circa 2010. (Or even of what the internal platform looks like now, as far as I know.)
Noogler: Haha, this video is so funny!
L4 SWE: (Crying because the video is so true)
L5 SWE: Haha, this video is so funny! I should show it to my interns, this will be a good training for them.
L6+ SWE: Why do people think this is funny? This Broccoli Man guy makes some really good points...
This whole field of scraping and anti-bot technology is an arms race: one side gets better at something, the other side gets better at countering it. An arms race benefits no one but the arms dealers.
If we translate this behavior into the real world, it ends up looking like https://xkcd.com/1499
I am not aware of any language (outside of intentionally-minimalist esolangs) that doesn't support floating point numbers. In some languages (like JavaScript) that's the only kind of number you get.
C is simple, to what today is nearly an absurd degree, but it at least integrates well with an enormous ecosystem of existing tooling and libraries. Go, by contrast, feels the need to re-invent every possible wheel, often with a seemingly intentional effort to be different just because.
C ABIs are rock solid on every platform. Any language or tooling in the world can load functions from a C library. By contrast, try calling Go from another language. You will quickly give up and use network protocols or subprocesses instead.
The converse is true too: on major platforms, the C library defines the operating system more than the kernel does. (I mean, in a Unix sytem, the entire libc is documented in the man pages. Documentation for writing C is literally built into the operating system.) By contrast, Go decides to avoid the standard platform ways of calling every operating system function, and instead implements syscalls directly into the kernel, basically just because Go hates interoperating with anything that's not Go.
C is a good language not because it is a good language, but because it is a good ecosystem. Unix and C are closely intertwined. (Even Win32 and C are pretty closely intertwined!) I could imagine a Go-based Plan9-like system -- if that existed, and had decades of engineering behind it, I could see the argument being made that Go's ecosystem compares to C's. But while Go may aspire to that, it isn't anywhere near there yet.
And when you start comparing Go with other languages on the basis of language features, I think Go fails laughably more often than not. (I'll give you "C++ is a clumsy mess", though.) But compare Go with Rust, with C#, with Haskell -- for that matter, compare Go with Java and I think Go is a less powerful, less useful language to write real code in.
If I want a lightweight, quick-and-dirty program, I'll use Python. If I want to write a reusable library that gets plugged into other software, I'd go with C (or at least write the interop layer in C). If I want a high-performance server, these days I would probably go with Rust. If I want a pragmatic, well-rounded language to write a large project in, I think C# would probably be my first choice.
What space does that leave for Go? Outside of microservices (where I contend that Rust is a much better choice, and there are lots of other options), Go's niche seems to be command-line tools. I sort of understand that, because Go's static linking makes redistributing binaries relatively easy (although Go by no means has a monopoly on that). But in the space of command-line tools, Go's argument handling is frankly bizarre: it looks at decades of precedent about what users expect from argument syntax and behavior and decides to throw it all away and reinvent the wheel.
I guess that means this comment (rant?) has ended up where it started: Go defies convention, basically "just because". By contrast, C defines convention. "If you like C, you will love Go"? Nope, not at all.