I agree with the author, and would summarize it like this.
XML is a markup language like HTML, and YAML is a data exchange format like JSON.
Markup languages are good for (surprise) marking up text. You start with text, and then layer structure and annotations on top of it with markup syntax. The markup syntax is verbose because it gives primacy to plain text, which is the default and requires no ceremony apart from escaping a few characters.
Markup languages are bad for configuration; data exchange languages are good for configuration. It just so happens that YAML is a bad data exchange format. It has many human-friendly do-what-I-mean features but they backfire when you actually mean something else (e.g. NO for Norway, not false).
A little off topic, but: I think your site sets the main text contentâs foreground color (something dark), but neglects to set its background color, letting my browserâs personal fallback settings for unspecified styles take over.
For unstyled sites, I have my fallback colors set to light-on-dark, so this half-enforced styling comes out as dark-on-dark.
Markup languages are bad for configuration; data exchange languages are good for configuration
Mostly agree, but I would go further and say
XML/HTML are for documents, JSON is for records / âobjectsâ, and CSV / TSV are for tables.
However, JSON is a pretty good data exchange language, but itâs not good for configuration because the syntax it too fiddly (comments, quoting, commas)
YAML is definitely not good for data exchange, and it has big flaws as a config language, but thereâs no doubt that many people use it successfully as a config language.
So config languages != interchange formats in my mind. Interchange formats are mostly for two programs to communicate (although being plain text helps humans too, so itâs a bit fuzzy.)
The space of config languages is very large, AND it blends into programming languages. Whereas JSON is clearly not a programming language (though it was derived from one)
Yeah that makes sense, config language deserves its own category. I guess Iâd say I prefer JSON over XML if those are your only two options (and I find it works well enough in VS Code for example, though they allow comments and trailing commas I think).
I think YAML is not suitable for data exchange, because of its complexity and shaky security record. Better to stick to JSON if you need text, or CBOR or protobufs etc. if you prefer binary. Good data exchange languages are bad config languages.
YAML is barely tolerable as a data input or configuration language, but there are better options such as json5. TOML is ugly and confusing but still better than YAML.
I wish more things would adopt UCL for configuration. Like YAML, it is a representation of the JSON object model but it also has a number of features that make it more useful as a configuration language:
Macros.
Include files.
Explicit merging rules for includes (replace objects, add properties to objects).
Cryptographic signing of includes, so you can use semi-trusted transports for them.
While I like UCL, it can turn into its own kind of hell. rspamd, for instance, is a fantastic piece of software, but the complex mass of includes and macros can make the configuration hard to reason about. Mind you, this isnât UCLâs fault, just something it enables.
The macros can be a bit exciting but I like the fact that rspamd doesnât have any defaults in the program, theyâre all visible in the config file directory thatâs included with the lowest priority.
Does Windows come with something like Shortcuts? AFAIK Microsoft havenât shipped any programming-like tools with their OS:es since DOS, but perhaps Iâve missed something?
Unless something has changed recently, Window Scripting Host has been a thing for decades, supporting both VBScript and JScript (MSâs JavaScript dialect).
I mean, itâs not well advertised, but itâs there.
Sure itâs not, but itâs as close to one as you can get. Unless you have a reason to store something in a local timezone, UTC is the right choice, but no choice is perfect.
The complicating issue is that timezones are typically stored as offsets, not timezones. This is why you should be sensitive to the time and should, if youâre storing a time in UTC, pay attention to the absolute time when converting back to the local timezone. The good thing is that this is still better than not using UTC because itâs a stable reference and the timezone database assumes itâs a stable reference.
So, store in UTC, but be aware you need to also use the timezone database properly. If you canât do that, store the datetime twice.
I need to doublecheck this, but Iâm pretty sure the timezone rules are additive. They wouldnât make sense otherwise. Thereâs a complication when it comes to future datetimes, but storing the revision of the timzone database wonât save you: thatâs an example of when you need to store things twice.
Also, not all countries to the way you think when it comes to Summer Time. Sometimes, the nonstandard time in in Winter.
My rule of thumb is, if you are recording a time in the past, then either use UTC or use the local time and the UTC offset. Donât use UTC if you need to record the time as it was displayed on the wall.
If you are storing a time in the future, then store the local time and the primary location. In many cases the tz name will do as a proxy for the location, but that will fail when tz boundaries change. You might also need to store some secondary locations so it is possible to detect when a plan might be disrupted by tz changes. You might need to store an earlier/later flag to disambiguate timestamps that occur when the clocks go back; alternatively use the Japanese syle of times like 26:30 for the small hours.
Wouldnât it be more robust to just store the time zone name and the tzdb version in use when the timestamp was made? Then, if a time zone is removed you can look up the offset and ask the user with a list of close timezones suggested.
I donât know any libraries that support recovering timezones from coordinates, it sounds more likely to need third party databases. Isnât there value in just sticking with the tzdb?
I donât know any libraries that support recovering timezones from coordinates
I wrote an application that gets IANA timezone from location names, so roughly the same problem. Itâs hard because there is no real database for this, so I use Wikidata; and had to fill a fair amount of timezones in Wikidata in the process.
Sometimes you need to dig into historical data to find where former district boundaries used to be. You have borderline bad quality data, eg. all of France is marked as having a timezone, but overseas departments and territories have their own so the timezone is actually for metropolitan France; but some parts are not specifically marked as such and only as part of France. Sometimes (especially in the US and Canada) a city uses the timezone from the state/province across the border. Sometimes itâs a county. Etc.
Yes, you need to record the tzdata version to detect problematic changes.
As I said, although the tz name will often do instead of the actual location (and standards like iCalendar require it), that will fail when tz boundaries change. Boundary changes are likely to happen when DST is abolished in Europe.
Officially, Irish Standard Time is summer time, and they have a negative DST offset in the winter. When tzdata was changed so that Europe/Dublin more accurately reflected Irish law, it was the first zone in the tz database with a negative DST offset. This caused a huge number of problems! As far as I know the change was not supposed to have any user-visible effect.
I really like the way that Smalltalk handles integers, which (I believe) is adopted from Lisp. Integers are stored with a tag in the low bit (or bits on 64-bit platforms). If they overflow, they are promoted to big integer objects on the heap. If you do arithmetic that overflows the fast path in Smalltalk, then your program gets slower. This doesnât mean that it canât lead to security vulnerabilities, but theyâre a less serious kind (an attacker can force you to allocate a huge amount of memory, they canât access arrays out of bounds). It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
This is not possible in C because C has to work in situations where heap allocation is impossible. If you write a+b in a signal handler, you may deadlock if the thread that received a signal in the middle of malloc, if addition is allowed to allocate memory to create big integer objects. If youâre using C in a situation where memory allocation is always fine, youâre probably using the wrong language.
Iâm pretty sure all Python objects are really pointers with their own object headers. âsmallâ integers (-5 to 256, inclusive) are statically allocated and most ways of getting these values will share them. Most, but not all:
>>> 7 is 6+1
True
>>> 7 is int('7')
True
>>> 7 is int.from_bytes(b'\x07', 'big')
False
but in any case theyâre still real objects which reside at real locations in memory. Python does use long arithmetic instead of its base-2**30 big integers when it can, but it doesnât have any other tricks to avoid allocation, as far as I know.
Accurate, but the parent comment is mainly around underlying implementation rather than the fact that Python does object interning for the sake of efficiency. The interning Python (and some other languages) does has unintended consequences though: I recall spending a whole hour convincing a developer I used to work with that == and is are not interchangeable. I literally had to show you them the C source to show exactly where the interning of small integers was happening before theyâd believe me.
Yeah, I went through all that, and thatâs what was so frustrating about it. 1 << 10 gets interned because it evaluates to a constant, as you noted. Constants are interned in addition to small numbers, hence why I ended up having to point all this out in the Python source code before I was believed.
It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
Wasnât JS famously developed during a weekend or something ⌠snark aside, it is a bit sad that so many people just accept the limitations of C instead of looking at other solutions.
A basic Scheme interpreter is really easy to implement over a couple of days, especially when youâve a full runtime to lean on for a bunch of the awkward bits. Converting the original LiveScript over to a C-like syntax probably took longer than the original interpreter.
Itâs a common mistake to confuse programming with typing. If someoneâs just sitting there staring into space, it doesnât look like theyâre doing anything useful. If theyâre rattling furiously on a keyboard, though, we assume theyâre achieving something. In fact, real programming often happens before the typing, and sometimes instead of it.
I often describe Go as a language which expects you to arrive at your editor with a well-defined plan already in mind. Itâs not a language that encourages or even really supports âexploratoryâ programming, like you might do in more REPL-oriented languages like Clojure, Ruby, or Python.
It was a design goal to make the compiler fast, absolutely. But I donât think the motivation for that goal was to support experimentation, I think it was primarily motivated by pain from the very slow compile times for large e.g. C++ and Java projects (at the time).
You could write a regex to make this apply to anything with garbage collection and not-too-many features. The author also carelessly (and offensively) misapplies the concept of, and the word, âTaoâ. Waterâs flowing may be itâs wu wei, itâs lack of doing, itâs being: the water is flowing downhill, rather downhill-ness being some innate property of the water. It doesnât have âa Taoâ. Tao isnât just âwork[ing] with the grainâ, itâs understanding the natural order that resulted in the grain to take the most effortless next action. I guess itâs just advertising copy so itâs not that important, but if I was a Taoist Iâd be pretty miffed
The Advent of Computing podcast recently had an episode covering the LGP-30, which had a bit-serial architecture. Itâs the machine made famous by The Story of Mel.
If youâre reading someoneâs (essentially) obit and donât know who they are, you can safely just keep going without this kind of inquiry. Suffice to say those who posted and are discussing know, and the question is (intentionally or not) insensitive.
She mostly grew up in notoriety in the golang and k8s community. I will not do a full eulogy, this is not the place, nor am i well placed for that.
But despite all the disagreements we may have with her, Nòva was a genuinely nice person to have in our community, pushing forward in interesting front, saying things that needed to be said, and in general someone a lot of us appreciated having in our communities.
No, they are not. Now, Googling her just results in a lot of people expressing sadness over her passing. I do not want to intrude on anyoneâs grief here, but Iâd never heard of her before and Iâve not been able to find any solid info about her life or work, just as @4ad below says.
@colindean above said she did the best talk of FOSDEM 2023. I was at that event, but Iâd never heard of her, nobody mentioned this talk, and Colin does not link it so I donât know for sure what talk it was.
Iâve googled that too â this is way more work than I should have to do, frankly â and I think it might be this one, but the blurb is fairly content-free and tells me nothing useful.
But the talk is also mentioned here and that gives a little context.
Apparently she ran Hachyderm. I hadnât heard of that, either. Apparently it is a Mastodon instance â I see little to distinguish these, TBH, and while Iâm on Mastodon/Fediverse, I find it little to no use. But David Calvert said:
mostly known for hosting the tech industry at hachyderm.io since Musk bought the bird site.
Thatâs more info than anywhere else in this thread.
Hachyderm is apparently
a safe space, LGBTQIA+ and BLM, primarily comprised of tech industry professionals world wide powered by Mastodon and ActivityPub.
She mightnât have been well-known amongst journos, but she was well known amongst developers and ops/infrastructure engineers.
Searching for her on Google and DDG, sheâs famous enough to warrant a sidebar on Google, and her website is above the fold on both. DDG gives better results, and also includes a link to her ORA authorâs profile above the fold. Sheâs definitely very Googlable.
Hachyderm was a side-gig. The blurb also wasnât content-free: the talk was about how she managed to scale out Hachyderm, which started as a personal Mastodon instance, in the face of a massive influx of users.
The Hacyderm talk she gave at FOSDEM earlier this year was on the main track, which was wedged, which is unusual for a non-keynote talk in Jansen. She also gave a talk about the Aurae low-level container runtime on the Rust track.
We should all remember that our lack of awareness of somebody does not mean that theyâre not well known.
Is it my imagination or are the python people simply stuck in the realm of single processing computing? Go has been able to do multi-core for like itâs whole existence. Same thing with rust, nim C. C. Sharp, I just never see why Python is such a popular language. Perhaps itâs just the good marketing.
The thing to remember is Pythonâs age and heritage. Itâs older than Java, and comes from the Unix tradition where if you wanted to do more than one thing at a time you forked a separate process for it.
So thatâs what Python did, and then Java happened. And Java did threading (because it was originally designed to run in environments that couldnât support true process-based multitasking), and Java marketing hype pushed threading as the one true way to do things, and suddenly threading was a thing people were demanding.
So Python added threading. But, at that stage of its history, one of Pythonâs big draws was the ease with which it could wrap around existing popular C libraries. And basically none of those wrappers were thread-safe, so Python had to make a tough decision/
The decision was to preserve as much backwards compatibility as possible, via the GIL. Which, at the time, seemed a reasonable tradeoff: the GIL primarily hurts you if your workload is pure Python and CPU-bound, and at that time most of what people wanted threading for was IO-bound workloads like network daemons and services. Plus, most people didnât have true multi-processor/multi-core hardware, and even if they did their operating system might not be able to use it (anyone remember how long it took to land Linux SMP, for example?).
Now, decades later, we all have multi-core/multi-processor computers in our pockets, and so it looks like a less reasonable tradeoff, but thatâs solely because of the benefit of hindsight.
Also, you mention Go, Rust, Nim and C# as examples of languages which somehow magically had the foresight to get it right⌠you might want to check when those languages first appeared, and compare to when Python did (and when Python had to make its threading choices).
You realise that Python is much older than Go, Rust, and Nim, right?
The GIL isnât an issue inherent to Python, but to the CPython C API. It exists because to make it easier for those writing C extensions that are not guaranteed to be threadsafe out of the box to be treated as threadsafe.
Go partly solved this issue by creating a largely isolated ecosystem. When you do need to reach to the outside world, the inevitable use of CGo is painful. Same for C#: .NET is its own isolated ecosystem. Rust has a complicated type system to cope with this, and the unsafe escape hatch where you really need to know what youâre doing.
Pythonâs âmarketingâ is that itâs a pleasant and approachable language. The real shame is that Python didnât starting out with a C API more like that of Lua or Tcl, but Lua is a younger language, and only got itâs current API in 4.0 when it was much less popular and breaking compatibility was thus less of an issue. I canât say much about Tcl historically except note on the current state of its C API.
The gap in your knowledge is a lack of a historical perspective. Theyâre not âstuck in the realm of single processingâ, itâs simply that nobody particularly wants to break the C API, and a lot of effort has been put into avoiding doing so in the past, but things are finally starting to give.
What bar needs to be cleared for a programming language to deserve existing? Code written in Python has been used to earn Nobel Prizes in the sciences.
Many people have great responses, but I just wanted to mention another aspect. When did you first own a computer that could execute two threads simultaneously?
I think I first had a hyper threading processor before I had multiple cores. That would then be the Pentium 4, released in 2002. That would make it 1/3 into the lifetime of Python up until now.
Another other thing that I think could be important is that threads were cheap on windows and processes were expensive. In Unix, a thread was not that much less expensive than a process. I remember the feeling of âthreads are for Windows where they canât handle many processes and canât spawn them quicklyâ.
POSIX threads were also only standardized in 1995. To decide on a cross platform implementation of threading, when windows didnât support POSIX threads natively, would have been tough to do. Especially for a feature that wasnât super useful for performance.
Another other thing that I think could be important is that threads were cheap on windows and processes were expensive. In Unix, a thread was not that much less expensive than a process. I remember the feeling of âthreads are for Windows where they canât handle many processes and canât spawn them quicklyâ.
IIRC, theyâre still expensive and require something like 1MB of memory per process at minimum.
Itâs much less than that. They typically require something like 2-8 MiB of address space for the stack, but that stack is lazily committed so youâre not consuming real memory unless you actually use all of the stack space. Beyond that, you typically have a few KiBs of kernel state for the thread (including register save area, which can be quite large with AVX or SVE), userspace thread structures, and userspace TLS. These rarely add up to more than a few pages.
I donât want to say that HTTP is a good RPC system or that it has all of the features of a proper one, but at a high level I think what a lot of people want out of their RPC is âmake fixed call, get results and/or statusâ. HTTP requests with JSON payloads work pretty well for this and they donât require, say, a connection setup phase the way a SMTP-like or IMAP-like protocol might have. At a low level HTTP can have keepalives and connection reuse and so on, but I think that tends to be either hidden away in the HTTP library or optional.
(Iâm the author of the original, linked-to entry.)
The words are all messed up at this point, but RPC traditionally meant mechanisms like âprocedure namingâ and âmarshal arguments and return valuesâ. Itâs designed to make remote procedure calls as convenient as local ones with respect to particular programming languages.
So Iâd say HTTP isnât RPC because itâs not designed for, or convenient for, that purpose.
You can make it do such things, but it takes extra work, and you also lose things like HTTP proxy support (middleboxes).
If HTTP were RPC, then you wouldnât have additional protocols like JSON-RPC tunneled inside HTTP. JSON-RPC specifies how your arguments and return values are marshaled.
If HTTP were RPC, you wouldnât have to say âHTTP POSTâ. Middleboxes understand HTTP verbs; they often donât understand your custom protocol inside HTTP. The network isnât just about the end points.
Likewise, TCP/IP isnât a protocol for hypertext, although you can use it that way. You have another layer with more semantics.
I get the reluctance but I still think itâs somewhat semantic from the serverâs perspective:
HTTP verbs are cache controls, which is not unusual for RPCs (otherwise would be done in request metadata/headers/etc)â middleboxes are generally aligned with this.
HTTP endpoints (or âresourcesâ) are encoded procedure names
To me, HTTP is a somewhat specialized kind of RPC (with specified caching and method encoding). We can of course build other kinds of RPCs on top of any RPC too.
We can draw the line elsewhere, but at the very least HTTP is very close to being an RPC. :)
I suppose the idea of âHTTP is RPCâ takes a minimalist definition of both termsâ RPC as in âit invokes procedures remotelyâ, and HTTP as in âa well-supported presentation layerâ.
In that HTTP is all about manipulating a large set of resources (nouns) with a very small set of fixed commands (verbs), and there are no remote procedures at a conceptual level at all.
Right. As I mentioned in a sibling comment, I think Iâm using a weaker definition of RPC than what youâre describing here. For me â and I think for most developers in this day and age â RPC is anything which is synchronous and follows request-response semantics. By this definition, all HTTP operations qualify. I understand this is not the original meaning.
Generics do take away probably 30% of my complaints with go. No sum types is still a big pain for me, theyâre just how I naturally model things. Iâve now used Go at work for 2 jobs in a row, and I legitimately donât like it (in a âmehâ way), but I am also completely productive in it. So Iâve really taken the stance that, minus some outlandish edge cases, language isnât all that important.
Like, writing a for loop vs using map feels really annoying at first, but the difference ends up being pretty superficial in the long run. I do not buy at all that switching to Haskell would drastically change my daily life as a programmer. And I literally love functional programming.
One other thing Iâd really like to see in Go is explicit interface conformance, i.e. type MyThing struct implements MyInterface. I know that defeats the whole purpose of implicit interfaces, which has other benefits (though they are lost on me), but at least make it optional. I always want to just look at something and see what it implements.
One other thing Iâd really like to see in Go is explicit interface conformance, i.e. type MyThing struct implements MyInterface.
Thereâs a hack to do it: either before or after the methods, add
var _ Iface = (*type)(nil)
If you write that first, the compiler will actually give you the steps, though just one at a time (e.g. missing method X, method X should have signature so and so, missing method Y, method Y should have signature so and so)
The âvar _ Ifaceâ should make it reasonably easy to find as well.
The lack of sum types is probably Goâs original sin. It left the language with nil, a clumsy way of approximating enumerations, and an error type thatâs gradually mutated into effectively a kind of checked except that you couldnât even check until 1.16, and now itâs as heavyweight as escape continuations anyway, and less convenient.
Ha! Fun question. You canât let the zero value be nil, or nil-ish â that would defeat the purpose of the sum type in the first place. And I suspect it would be infeasible to prevent the construction of zero-value sum types altogether â such a constraint would require an enormous number of language changes. I guess the only remaining option is for the zero value of a sum type to be the zero value of the first type in its type list. So the zero value of int | string would be int(0). Thatâs not particularly satisfying!
Yeah, itâs hard to retrofit onto Go as it exists now. I think you can sort of squint and imagine a version of Go where it has undefined and you need to be able to statically show that something is not undefined before youâre allowed to read from it. So var x union{string, int}; f(x) would be illegal at compile time because x is undefined. But it starts to look more like ânot Goâ the more you think it through.
Go pretty much already has the answer, in the interface extension to type sets for generic bounds: a sum type in Go would likely be relaxing the language to allow interface { int | string } to be used as a regular type (currently itâs only allowed for trait bounds), and adding support for type refinement & exhaustiveness to type switches.
This means the zero value would be the nil interface.
Unless Go specifically removed nil interfaces & default values from such a type, but I donât see that happening given how far it would cascade through the language. Not unless the team decided to completely overhaul default values in Go 2 anyway. Which Iâd hope but would not hold my breath for.
There are a whole bunch of different types where a zero value makes little sense, and we donât even have to be talking about sum types. The fact they interact poorly by default isnât even necessarily a bad thing, and if a language designer so deemed it useful, theyâre could just allow a constructor to be nominated as the default one.
Generics solve your last problem because interfaces are type constraints so you can use a function with an empty body to assert to the compiler which interfaces you intend a type to implement.
Golang will soon be as bloated as any other language that makes bold claims from the start and then spends itâs later years backsliding to try and draw in itâs critics.
I certainly have that concern too. However, from what Iâve seen, the Go team continues to be judicious and cautious in its choice of what to include. The only language change to speak of has been the addition of generics in 1.18. All other changes are in the standard library and the tooling, which as far as I can tell just keep getting better. It doesnât have the same design-by-crowd/committee feeling as Python has had in recent years.
This is an odd criticism of Go in general and this coroutine proposal specifically, I think. Itâs proposing a standard library package which happens to lean on runtime support for performance reasons only. Go has an HTTP server in its standard library. Being a batteries-included language seems to be out of favour at present, but this would seem to be an example of Go (quite correctly, imho) swimming against the tide and including batteries anyway.
Iâm not sure what theyâve backslid on. People bring up generics a lot, but prior to the successful generics design, the Go FAQ had said:
Generics may well be added at some point. We donât feel an urgency for them, although we understand some programmers do.
for what, a decade?
Full disclosure, I donât think Go is a good language. But I feel like theyâve been remarkably consistent on scope and feature creep.
Yeah, itâs kind of silly for Goâs critics to claim that Go is a bloated language when the only real piece of bloat that has been added has been generics and its critics positively screamed for that for over a decade.
The critics who are concerned that Go is becoming bloated, and the critics who screamed for generics, are different people.
(A lot of social phenomena make a lot more sense when you consider that what looks like one group from the outside is actually several groups, each with different thoughts and motivations.)
I remember when Goâs critics were arguing that its simplicity claims were easy to make as it was a new language, but âgive it 10 years and it will be as bloated as Java/Python/C++/etcâ, well it has been 14 years since Go debuted and it remains pretty bloat-free (generics is the only real bit of bloat added to the language, and that was positively demanded by Goâs critics). Itâs nice to see that people are still making this same argument 14 years later. :)
This is hardly bloat. Itâs quite close to Luaâs asymmetric coroutines and Pythonâs (synchronous) yield statement, which are both solid designs with minimal overhead.
Contrariwise, it seems they are doing an admirable (if quite slow) job of growing their language. I look forward to the addition of macros, inheritance, gradual typing, and unrestricted compile-time computation.
I donât know â Go goes against almost everything in that absolutely great talk. A core tenet of which is that one should be able to write a library that can seamlessly extend a language. Go has real trouble around it with an over reliance on built-ins.
Itâs no accident that Guy Steele worked on Java and later on Scheme (among others). Scheme is a more niche language and while the above core tenet definitely well-applies to that language, I would highlight Java over Go in this this gradual growth regard, given its longer life and extensive use, and if anything, thatâs its core strategy: last movers advantage. The team really well evaluates which language features are deemed âsuccessfulâ after they were tried out by more experimenting PLs.
A core tenet of which is that one should be able to write a library that can seamlessly extend a language. Go has real trouble around it with an over reliance on built-ins.
The coroutine library described in the article is a library.
Itâs no accident that Guy Steele worked on Java and later on Scheme (among others).
I think you have this backwards. He worked on scheme in the 70s and Java was created in the 90s. Not exactly sure when Steele got involved in Java though. I know his big contribution was generics, but I imagine you have to do some work before you get invited to do something so major.
His contribution was the Java Language Specification, among other things. He was one of the original team of 4 (James Gosling, Guy Steele, Bill Joy, and maybe Arthur van Hoff, the namesake of Javaâs AWT package a la âArthur Wants Toâ). Heâs still at Sun/Oracle Labs (his office was right next to mine).
Heâs also known for Lambda The Ultimate (LTU), a series of papers that he published in the 70s, I think. (Thereâs a website by that name, inspired by those papers, and focused on PL topics.) And a bunch of other things heâs been involved with over the years at and around MIT. Including square dancing.
until recently with some significant breakthrough, his name was still on the paper defining how to cast a float to a string precisely (minimal length round trip safe conversion).
To be fair. This technique was probably known before hand, and the co-author, Dyvbig iirc, probably did more work than him. But still.
Oh this algorithm is every where. Like nearly all libc.
He was one of the original team of 4 (James Gosling, Guy Steele, Bill Joy, and maybe Arthur van Hoff, the namesake of Javaâs AWT package a la âArthur Wants Toâ).
Ah! Thatâs interesting! Wikipedia only lists Gosling as the designer. I double checked the wiki page for Java before posting, but I guess it doesnât tell the whole story. Thank you for the clarification!
I guess the sarcasm didnât quite come throughâŚ
That said, Iâm actually somewhat curiousânot really knowing either language particularly wellâin what respects java is more expressive and orthogonal than go. Both added generics after their initial release, are garbage-collected (though java is much better at it), have some semblance of first-class functions, have some semblance of generic interfaces, and have some cordoned-off low-level primitives. Both are sufficiently expressive and capable that most of their infrastructure is written in itself (contrast with, say, python); hotspot happens to be written in c++, but this seems more a consequence of historical factors, and istr cliff click said that if he were writing hotspot today, he would write it in java. Java has inheritance and exceptions, where go does not; are there other major differences?
Go has goroutines which Java is soon to get. Go has value types and value/pointer distinction, which Java is maybe getting at some point
The biggest difference is that Java (in a typical implementation) is a fairly dynamic language, while Go is a fairly static one. Dynamically loading classes into your process is the Java way. Java is open-world, Go is closed-world.
I feel the last property is actually the defining distinction, as language per se doesnât matter that much. I do expect Go & Java to converge to more-or-less the same language with two different surface syntaxes.
I donât follow too closely, but my understanding is that green threads (the current reincarnation of) are fairly recent (work started 2017), and are almost there (you can already use them, they are implemented, but not yet stabilized).
Work on value types I think started in 2014, and it seems to me that thereâs no end in sight.
The green threads work started a lot earlier than 2017. Not sure when it got staffed in earnest, but the R&D had been going on for a while before I left in 2015.
Itâs called the Loom project. It is already available in preview for a few Java versions, so you can also play with it. The cool thing about it is that it uses the same APIs as the existing Thread library, so in many cases you can just change a single line to make use of it.
I canât tell if the sarcasm here is âyou think Go is becoming bloated very quicklyâ or âGo is never going to add these features (and thatâs a bad thing)ââŚ
One thing that I think a lot of people forget about is directly booting a kernel with your bolted on executable. They tend to be very small and very effective. Theyâre just a little bit hard to make.
Kind of the opposite. That was what was called a âdos extenderâ which basically was a combination of an extended init that gets the CPU in 32bit protected mode (which could coordinate with other popular software that may interfere with doing so the easy way), a small runtime to call into v86 mode so that you could still use DOS for file access and call the VGA BIOS, and some library code to talk to it. DOS/4G was a standalone one that was pretty expensive, so wasnât very common, but DOS/4GW was the same product bundled in with Watcom C++ and was everywhere.
Iâm failing to understand what this has to do with the article? The submission is about how Firecracker is designed for the kind of workload that might work for, but is a very poor fit for the dev environment use case.
I think the main thought that I had was around micro VMs. It might have been a bit longitudinal in the sense that itâs not a build agent, but I am betting that a micro VM would be another valid use case for a very fast build server.
Good! Iâve loathed the .egg format for so very long. One day, hopefully not so far in the future, setuptools and everything associated with it will, with any luck, shrivel down to something much smaller and much more sane. Preferably, itâll just go away completely.
was once rejected from a job specifically because I mentioned Erlang and the founder said he thought I was more of a computer scientist than an engineer
Thatâs interesting, because thereâs a fair amount of Erlang used in industry â it was created for telephone switching systems, not as an academic exercise. CouchDB is mostly written in it. Is Kafka in Erlang or am I misremembering?
As to your main point, Iâm not a Lisper, and to me the quotes you gave tend to reflect my feelings: stuff that once made Lisp special is widely available in other languages, the cons cell is a pretty crude data structure with terrible performance, and while macros are nice if not overused, theyâre not worth the tradeoff of making the language syntax so primitive. But I donât speak from a position of any great experience, having only toyed with Lisp.
Can you elaborate? Arenât lists the primary data structure, in addition to the representation of code? And much of the Lisp code Iâve seen makes use of the ability to efficiently replace or reuse the tail portion of a list. That seems to practically mandate the use of linked lists â you can implement lists as vectors but that would make those clever recursive algorithms do an insane amount of copying, right?
Arenât lists the primary data structure, in addition to the representation of code? And much of the Lisp code Iâve seen makes use of the ability to efficiently replace or reuse the tail portion of a list
No. Most lisp code uses structures and arrays where appropriate, same as any other language. Iâm not sure what lisp code youâve been looking at, so I canât attest to that. The primordial LISP had no other data structures, it is true, but that has very little to do with what we would recognise as lisp today.
I think it stems mostly from how Lisp is taught (if itâs taught at all). I recall back in college when taking a class on Lisp it was all about the lists; no other data structure was mentioned at all.
Thatâs a popular misconception, but in reality Common Lisp, Scheme, and Clojure have arrays/vectors, hashtables, structures, objects/classes, and a whole type system.
I donât know what Lisp code youâve looked at, but in real projects, like StumpWM or the Nyxt browser or practically any other project, lists typically donât play a big role.
Unfortunately, every half-assed toy language using s-expressions gets called âa Lispâ, so thereâs a lot of misinformation out there.
Clojure and Fennel and possibly some other things donât used linked lists as the primary data structure. Both use some kind of array, afaik (Iâve never properly learned Clojure, alas). How this actually works under the hood in terms of homoiconic representation I am not qualified to describe, but in practice you do code generation stuff via macros anyway, which work basically the same as always.
As I said above, this is a divisive issue for some people, but Iâd still call them both Lispâs.
Depends a bit on the personâs perspective. Iâve seen some people get absolutely vitriolic at Clojure and Fennel for ditching linked lists as the primary structure. I personally agree with you, but apparently it makes enough of a difference for some people that itâs a hill worth dying on.
I donât think Kafka is, but CouchDB certainly is and, famously, WhatsApp. Itâs still not so common but not unheard of, especially now in the age of Kubernetes, although ElixĂr seems reasonably popular. Either way I donât think most people know much about its history, they just sort of bucketize it as a functional language and whatever biases they have about them
I never actually wrote much Erlang â I only even mentioned it in that interview because the founder mentioned belonging to some Erlang group on his LinkedIn. It turned out to have been something from his first startup, which failed in a bad way, and I think he overcorrected with regard to his attitude toward FP. He was a jerk in any case
I want this back, because WebAuthn is far to complex and adds the problem that the Website and the backend has to implement the authentication. With KEYGEN all about the keys is handled by the browser. The authentication check then can be done by the httpd.
Yes I know there are some issues with the UI and other issues on implementation side. But this is nothing conceptional and can be improved.
To your other comment about storing the credential on separate device: What stops a browser from doing the same thing with keys generated by KEYGEN?
All Iâve seen from the WebAuthn world has made it seem like an excellent way to lock yourself into either Googleâs or Appleâs ecosystem as you he two companies demand to control all your online accounts. Where does the person who uses Android on their phone, macOS on their laptop and Linux on their desktop fit in to this brave new world?
If only! At $WORK, we use WebAuthn for SSO, and we use YubiKeys as the second factor. We explicitly set âusbâ as the only allowed transport because we require people to use their YubiKeys to generate their WebAuthn token. However, neither Chrome nor Safari respect this and will instead try to get the user to register a passkey instead, which naturally wonât work. And the token registration UIs in both are actively hostile to using any methods other than passkeys. Firefox is at least better in this regard, but possibly only because its WebAuthn support is less extensive.
Alright but Iâm not going to be using Yubikeys. So how do I sync my passkeys between my phone and desktop, so that I can log in to any account without the involvement of the other device?
Nothing in WebAuthn adds a dependency on anything other than your computer. On Windows, the private keys are stored in the TPM, on macOS theyâre stored in the Secure Element, and on Android devices theyâre stored in whatever the platform provides (a TrustZone enclave in the worst case, a separate hardware root of trust in the best case). All of these are defaults and, as far as Iâm aware, all support using an external U2F device as well. At no point does Apple or Google have access to any my WebAuthn private keys. On other platforms, itâs up to the platform how it stores the keys, but I believe the TPM is pretty well supported on Linux.
Aaaaand by what mechanism are the keys synced between my iPhone and my Linux desktop?
I need to be able to create an account on my Linux desktop (which doesnât have a TPM, by the way) and then log in to that account with my iPhone (without the involvement of the desktop at the time of login). I also need to be able to create an account on my iPhone and then log in to that account with my desktop (without the involvement on my phone at the time of login). This is no problem using passwords and password managers. My understanding is that itâs impossible with WebAuthn.
Aaaaand by what mechanism are the keys synced between my iPhone and my Linux desktop?
They arenât. By design, there is no mechanism to remove the keys from secure storage. If there were, an OS compromise could exfiltrate all of your keys instantly. You create a key on one device and use that to authorise the next device. Alternatively, you use a U2F device and move it between the two machines (I believe iOS support U2F devices over NFC, your Linux machine definitely supports them over USB).
my Linux desktop (which doesnât have a TPM, by the way)
Are you sure? Most vaguely recent motherboards have one (at least an FTPM in the CPU). Without one, thereâs no good way of protecting LUKS keys, so that might be something to look for in your next upgrade.
You seem very interested in pushing this U2F device thing. I donât know how many times I need to say Iâm uninterested.
And if I canât create an account on one device and then log in on another device without the first device involved, this is not something for me. What do I do if I make an account on my phone, happen to not log in to it on anything other than my phone, but then my phone breaks and I need to log in on my desktop? Is that just ⌠not supported anymore?
And why should I think Appleâs implementation will even allow me to authorize my Linux machine? Is that something which falls naturally out of the standard or has Apple publicly committed to it or are you just hoping theyâll be nice?
⌠TPM âŚ
Are you sure? Most vaguely recent motherboards have one
I just know my (rarely used) Windows install doesnât let me upgrade to 11 due to missing TPM. Also, older hardware is a thing.
You seem very interested in pushing this U2F device thing. I donât know how many times I need to say Iâm uninterested.
You need to store keys somewhere. You have three choices:
In software, where anything that can compromise that software layer can exfiltrate them. Check the number of CVEs in the Linux kernel that would allow an attacker to do this before you think itâs a good idea (not particularly singling out Linux here, any kernel that is millions of lines of C is going to be compromised)l
In some hardware tied to the device (TPM, Secure Element, whatever). This is convenient for the device and gives you some security in that an OS compromise lets an attacker launch an online attack but not exfiltrate keys (these things often do some rate limiting too). The down side is that itâs tied to the device.
Iâm some external hardware that you can move between devices. The standard for these to interface with computers is called U2F.
And if I canât create an account on one device and then log in on another device without the first device involved, this is not something for me. What do I do if I make an account on my phone, happen to not log in to it on anything other than my phone, but then my phone breaks and I need to log in on my desktop? Is that just ⌠not supported anymore?
Thatâs what WebAuthn recovery codes are for. Store them somewhere safe and offline.
And why should I think Appleâs implementation will even allow me to authorize my Linux machine?
I have no idea what this even means. Apple, Google, Microsoft, and Mozilla implement the client portion of WebAuthn. They have no control over which other devices any WebAuthn provider lets you use, just as a recommendation to use a strong password in Safari has no impact if you reset the password in Chrome or Edge.
You seem to think WebAuthn is something completely different to what is actually is. I canât really help unless you explain what you think it is so that I can understand how you get to the claims youâre making.
I just know my (rarely used) Windows install doesnât let me upgrade to 11 due to missing TPM. Also, older hardware is a thing.
I believe Windows 11 requires a TPM 2.0 implementation. TPM 1.x is fine for these uses and is 14 years old at this point.
I also donât have a need for LUKS.
You place a lot of faith in your physical security.
I have tried to read up on WebAuthn actually, and have never found out how they intend transfer of identities between devices to work. It leads me to believe that youâre either supposed to have one device (the phone) be the device which authenticates (similar to how 2FA systems work today), or sync keys using some mechanism thatâs not standardised. But it sounds like you believe thereâs another mechanism; can you explain or link to some documentation on how thatâs supposed to work?
Nothing stops you from having multiple keys with a single account, IIRC. You could have one device initially authorize you on another system and then make a new key for the other device.
You havenât read that because it is out of scope for WebAuthn. WebAuthn provides a mechanism for permitting a remote device to attest to its userâs identity. It is up to the implementer of the server-side part to provide a mechanism (beyond recovery codes) to add a second device. The normal way of doing this is to use one device to enrol another. For example, you try to log in on your computer, it shows a 2-3 digit number, then you log in on your phone and approve, now both devices are authorised.
If your objection to WebAuthn is that the higher-level flows that people build on top of it have problems then you should direct your criticisms there.
Honestly, Iâm not sure it would be that usable by modern standards. I donât think anything other than RSA was widely supported, and then limited to 2048 bit key sizes, etc. It would need a lot of modernisation. I wonder if the web crypto API can provide any suitable alternatives? Not sure if it has facilities for local key storage.
The limit to RSA and 2048 bit key size is just a implementation limit. Of course this should be improved. The charming part of this is, the website donât has to interact with the key. Yes I know there are some issues with TLS client auth, but with auth optional this can improved.
Exceptions are values in Python. Iâm not sure where the notion that theyâre not could come from. This is an issue is flow control. Go has one kind of escape continuation, which is triggered by the return statement, where as Python has two: the one triggered by return and the one triggered by raise. However, both of these handle values.
I think what itâs traditionally intended by âerrors are values in Goâ is related to the way they are being handled, not produced. In languages where error escaping is done with exceptions, in this case Python, they are usually handled by type, not by value.
try:
raise NameError('HiThere') # raise by value
except NameError: # handle by type
print('An exception flew by!')
raise
When you use the likes of fmt.Errorf() youâre minting new objects, just as you do with calling an exception typeâs constructor. The difference is that you have basic pattern matching (because thatâs what an exception handler does) on the type, allowing you to discriminate between them, which you canât do with the likes of fmt.Errorf().
I think youâre looking to closely at specifics, rather than the gist of it: errors are handled using the same language features as other values, unlike exceptions which are handled using dedicated language constructs. Python doesnât do return Exception even if it could.
This is not accurate. Go tuples are an error-specific language feature in the same as way Pythonâs except. You canât use tuples as a general construct.
Go doesnât have tuples, but it does have multiple return values. Often the last return value is an error, but thatâs not a language feature or requirement or anything, itâs just a convention. So I think the OP is accurate.
Thereâs a strong convention to use it like that, but Go lets you use it with any type you want. You could use it to return e.g. (x,y) coordinates if you wanted.
Go dropped the ball on having special-case multiple-value return instead of just single-value return with tuples and destructuring, but having âsimpleâ non-generalizable features is sort of their thing.
But even when used with errors, if err != nil is definitely spiritually closer to if (ret != -1) than try/catch.
Go doesnât have first class tuples, but its return tuples are not specific to error handling. You can return two ints; or an int, a bool, and a float; or whatever else.
Sure, by its nature this is true, because itâs a tuple. But with non-error types you have multiple ways to return them, whereas errors are always returned using the tuple special-case. Tuples exist to return errors.
Iâm not sure what youâre saying. As a convention, people return errors as the last type in a tuple, but itâs just a convention. You can return them through global values (like C errno) or out value pointers instead if you wanted to. I have a couple of helper functions that take error pointers and add context to the thing they point at. And people return other things in tuples, like bools or pairs of ints. Itâs a historical question whether multiple return was intended for errors, but I do know that before Go 1.0, the error type was a regular type in the os package and it was only promoted to a built in when Roger Peppe (who doesnât work at Google AFAIK) proposed doing so.
Out of curiosity, I dug up the original public introduction from 2009. To my surprise, Pike made it entirely through that presentation without ever mentioning error-handling that I can find.
So, I hit the wayback machine. The very first introduction of function tuples on the website uses error returns as the use-case. This slide deck from Pikeâs Go course also introduces multiple returns with error handling.
I donât think itâs fair to say this is just a convention, it is how the designer of the language chose to introduce the feature to people for the first time.
The distinction worth making here is not that âerrors are valuesâ, that is uninteresting. Itâs true in Python. The distinction is non-local returns vs multivariate functions.
Youâre describing multiple return values as âfunction tuplesâ. I donât think this is really accurate, as those return values are always discrete. Go doesnât really have a concept of a tuple.
The thing that âerrors are valuesâ tries to communicate isnât any detail about the specific implementation of the error type, but rather that errors are not fundamentally different than other types like ints or structs or whatever, and that error handling can and should use the same language constructs as normal programming.
In Python, exceptions are values, but theyâre not just values; theyâre values that interact with the exception-handling mechanism, which does things to and with them (unlike return, which doesnât care what kind of value you give it, and doesnât modify that value).
I thought this was an interesting compare-and-contrast of Python package management with Node and C#. Being a relative newbie to Python packaging, Iâm never 100% sure if something is confusing because I havenât invested the time to learn it yet, or if itâs confusing because itâs actually more complex than it needs to be. The author echos some frustrations Iâve personally felt but couldnât quite articulate myself.
The biggest surprise to me was that the author argued against virtualenvs! Iâve always assumed that venvs were a necessary evil, and that the way to address their rough edges was to use a tool that manages them for you (like pipenv or Poetry). This blog article is the first place Iâve heard of PDM or PEP 582 â my inclination is to go with the crowd and stick with Poetry (or any more-popular tool that displaces it), but I wish luck to everyone involved in replacing the venv model with something simpler.
They currently are a necessary evil, because something like PEP 582 requires a bunch of buy-in that virtual environments donât. They were a solution to a problem that didnât require any action from anyone but the user.
I donât disagree! Mind you, virtualenv was a revelation back in the day. Itâs just a pity the core team have a history of what is at best benign neglect when it comes to packaging, which lead to the setuptools debacle, and how it was left to rot for years after PJE became a motivational speaker. A lot of the problems with the Python ecosystem can be traced to that abandonment.
I agree with the author, and would summarize it like this.
XML is a markup language like HTML, and YAML is a data exchange format like JSON.
Markup languages are good for (surprise) marking up text. You start with text, and then layer structure and annotations on top of it with markup syntax. The markup syntax is verbose because it gives primacy to plain text, which is the default and requires no ceremony apart from escaping a few characters.
Markup languages are bad for configuration; data exchange languages are good for configuration. It just so happens that YAML is a bad data exchange format. It has many human-friendly do-what-I-mean features but they backfire when you actually mean something else (e.g. NO for Norway, not false).
How dare you RTFA and summarize it better than I made it. I am deeply offended by this breach of commenting etiquette. đ
A little off topic, but: I think your site sets the main text contentâs foreground color (something dark), but neglects to set its background color, letting my browserâs personal fallback settings for unspecified styles take over.
For unstyled sites, I have my fallback colors set to light-on-dark, so this half-enforced styling comes out as dark-on-dark.
https://cdn.imgchest.com/files/wye3cp2g5w4.png
Iâm just a guest blogger, but Iâll pass it along.
Mostly agree, but I would go further and say
However, JSON is a pretty good data exchange language, but itâs not good for configuration because the syntax it too fiddly (comments, quoting, commas)
YAML is definitely not good for data exchange, and it has big flaws as a config language, but thereâs no doubt that many people use it successfully as a config language.
So config languages != interchange formats in my mind. Interchange formats are mostly for two programs to communicate (although being plain text helps humans too, so itâs a bit fuzzy.)
The space of config languages is very large, AND it blends into programming languages. Whereas JSON is clearly not a programming language (though it was derived from one)
https://github.com/oilshell/oil/wiki/Survey-of-Config-Languages
Yeah that makes sense, config language deserves its own category. I guess Iâd say I prefer JSON over XML if those are your only two options (and I find it works well enough in VS Code for example, though they allow comments and trailing commas I think).
I think YAML is not suitable for data exchange, because of its complexity and shaky security record. Better to stick to JSON if you need text, or CBOR or protobufs etc. if you prefer binary. Good data exchange languages are bad config languages.
YAML is barely tolerable as a data input or configuration language, but there are better options such as json5. TOML is ugly and confusing but still better than YAML.
I wish more things would adopt UCL for configuration. Like YAML, it is a representation of the JSON object model but it also has a number of features that make it more useful as a configuration language:
While I like UCL, it can turn into its own kind of hell. rspamd, for instance, is a fantastic piece of software, but the complex mass of includes and macros can make the configuration hard to reason about. Mind you, this isnât UCLâs fault, just something it enables.
The macros can be a bit exciting but I like the fact that rspamd doesnât have any defaults in the program, theyâre all visible in the config file directory thatâs included with the lowest priority.
Does Windows come with something like Shortcuts? AFAIK Microsoft havenât shipped any programming-like tools with their OS:es since DOS, but perhaps Iâve missed something?
Unless something has changed recently, Window Scripting Host has been a thing for decades, supporting both VBScript and JScript (MSâs JavaScript dialect).
I mean, itâs not well advertised, but itâs there.
(This is partially TL;DR)
Sure itâs not, but itâs as close to one as you can get. Unless you have a reason to store something in a local timezone, UTC is the right choice, but no choice is perfect.
The complicating issue is that timezones are typically stored as offsets, not timezones. This is why you should be sensitive to the time and should, if youâre storing a time in UTC, pay attention to the absolute time when converting back to the local timezone. The good thing is that this is still better than not using UTC because itâs a stable reference and the timezone database assumes itâs a stable reference.
So, store in UTC, but be aware you need to also use the timezone database properly. If you canât do that, store the datetime twice.
I need to doublecheck this, but Iâm pretty sure the timezone rules are additive. They wouldnât make sense otherwise. Thereâs a complication when it comes to future datetimes, but storing the revision of the timzone database wonât save you: thatâs an example of when you need to store things twice.
Also, not all countries to the way you think when it comes to Summer Time. Sometimes, the nonstandard time in in Winter.
My rule of thumb is, if you are recording a time in the past, then either use UTC or use the local time and the UTC offset. Donât use UTC if you need to record the time as it was displayed on the wall.
If you are storing a time in the future, then store the local time and the primary location. In many cases the tz name will do as a proxy for the location, but that will fail when tz boundaries change. You might also need to store some secondary locations so it is possible to detect when a plan might be disrupted by tz changes. You might need to store an earlier/later flag to disambiguate timestamps that occur when the clocks go back; alternatively use the Japanese syle of times like 26:30 for the small hours.
Wouldnât it be more robust to just store the time zone name and the tzdb version in use when the timestamp was made? Then, if a time zone is removed you can look up the offset and ask the user with a list of close timezones suggested.
I donât know any libraries that support recovering timezones from coordinates, it sounds more likely to need third party databases. Isnât there value in just sticking with the tzdb?
I wrote an application that gets IANA timezone from location names, so roughly the same problem. Itâs hard because there is no real database for this, so I use Wikidata; and had to fill a fair amount of timezones in Wikidata in the process.
Sometimes you need to dig into historical data to find where former district boundaries used to be. You have borderline bad quality data, eg. all of France is marked as having a timezone, but overseas departments and territories have their own so the timezone is actually for metropolitan France; but some parts are not specifically marked as such and only as part of France. Sometimes (especially in the US and Canada) a city uses the timezone from the state/province across the border. Sometimes itâs a county. Etc.
Here is the part that gets the timezone from an OSM id, if you are interested: https://github.com/progval/Limnoria/blob/5357f50bed9a830994faf663416c4b05b21f00b0/plugins/Geography/wikidata.py
Yes, you need to record the tzdata version to detect problematic changes.
As I said, although the tz name will often do instead of the actual location (and standards like iCalendar require it), that will fail when tz boundaries change. Boundary changes are likely to happen when DST is abolished in Europe.
Southern Hemisphere says hi!
Officially, Irish Standard Time is summer time, and they have a negative DST offset in the winter. When tzdata was changed so that Europe/Dublin more accurately reflected Irish law, it was the first zone in the tz database with a negative DST offset. This caused a huge number of problems! As far as I know the change was not supposed to have any user-visible effect.
Wow, TIL. Thanks for this info.
Another reminder that normalisation doesnât mean you can forego validation.
I really like the way that Smalltalk handles integers, which (I believe) is adopted from Lisp. Integers are stored with a tag in the low bit (or bits on 64-bit platforms). If they overflow, they are promoted to big integer objects on the heap. If you do arithmetic that overflows the fast path in Smalltalk, then your program gets slower. This doesnât mean that it canât lead to security vulnerabilities, but theyâre a less serious kind (an attacker can force you to allocate a huge amount of memory, they canât access arrays out of bounds). It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
This is not possible in C because C has to work in situations where heap allocation is impossible. If you write
a+b
in a signal handler, you may deadlock if the thread that received a signal in the middle ofmalloc
, if addition is allowed to allocate memory to create big integer objects. If youâre using C in a situation where memory allocation is always fine, youâre probably using the wrong language.This is how Python also works.
There was a proposal to add it to Go, but it never went anywhere because it would break existing code. https://github.com/golang/go/issues/19623
Iâm pretty sure all Python objects are really pointers with their own object headers. âsmallâ integers (-5 to 256, inclusive) are statically allocated and most ways of getting these values will share them. Most, but not all:
but in any case theyâre still real objects which reside at real locations in memory. Python does use long arithmetic instead of its base-2**30 big integers when it can, but it doesnât have any other tricks to avoid allocation, as far as I know.
Accurate, but the parent comment is mainly around underlying implementation rather than the fact that Python does object interning for the sake of efficiency. The interning Python (and some other languages) does has unintended consequences though: I recall spending a whole hour convincing a developer I used to work with that
==
andis
are not interchangeable. I literally had to show you them the C source to show exactly where the interning of small integers was happening before theyâd believe me.Tricky: I thought using a big enough number would make this obvious:
but this one comes out TrueâŚ
Ok, so Iâll try even bigger numbers, but Iâll factor out N first:
wat (:
Apparently itâs constant folding, and then sharing the constant:
Yeah, I went through all that, and thatâs what was so frustrating about it.
1 << 10
gets interned because it evaluates to a constant, as you noted. Constants are interned in addition to small numbers, hence why I ended up having to point all this out in the Python source code before I was believed.Wasnât JS famously developed during a weekend or something ⌠snark aside, it is a bit sad that so many people just accept the limitations of C instead of looking at other solutions.
From my vague recollections, it was originally meant to be Scheme with Java syntax, so not knowing how Lisp did numbers was a bit surprising.
A basic Scheme interpreter is really easy to implement over a couple of days, especially when youâve a full runtime to lean on for a bunch of the awkward bits. Converting the original LiveScript over to a C-like syntax probably took longer than the original interpreter.
I particularly appreciate this bit at the end:
I often describe Go as a language which expects you to arrive at your editor with a well-defined plan already in mind. Itâs not a language that encourages or even really supports âexploratoryâ programming, like you might do in more REPL-oriented languages like Clojure, Ruby, or Python.
Some may disagree with that description. Wasnât one of the design goals to make the compiler fast to support quick iteration and experimentation?
It was a design goal to make the compiler fast, absolutely. But I donât think the motivation for that goal was to support experimentation, I think it was primarily motivated by pain from the very slow compile times for large e.g. C++ and Java projects (at the time).
Is this actually specific to Go? I feel like it could be about nearly any language from the 1980s.
You could write a regex to make this apply to anything with garbage collection and not-too-many features. The author also carelessly (and offensively) misapplies the concept of, and the word, âTaoâ. Waterâs flowing may be itâs wu wei, itâs lack of doing, itâs being: the water is flowing downhill, rather downhill-ness being some innate property of the water. It doesnât have âa Taoâ. Tao isnât just âwork[ing] with the grainâ, itâs understanding the natural order that resulted in the grain to take the most effortless next action. I guess itâs just advertising copy so itâs not that important, but if I was a Taoist Iâd be pretty miffed
Donât be miffed. Mabye youâre already a Taoist dreaming that youâre a WilhelmVonWeiner.
But then you get only 1% of the clicksâŚ
Given Go is essentially a reskin of Algol 68âŚ
What isnât, these days?
The Advent of Computing podcast recently had an episode covering the LGP-30, which had a bit-serial architecture. Itâs the machine made famous by The Story of Mel.
Not to be insensitive to anyone, but who is this?
Thank you for saying this, because I had the same question.
If I had to post just one thing, I think this essay explains it best :
https://hackingcapitalism.io/why/
If youâre reading someoneâs (essentially) obit and donât know who they are, you can safely just keep going without this kind of inquiry. Suffice to say those who posted and are discussing know, and the question is (intentionally or not) insensitive.
Iâd ask you to look at it differently: if asked politely, a genuine inquiry is a good way to honor somebody.
We all die two deaths: when we cease living, and when we are no longer remembered.
If a stranger asks in passing about the subject of a public mourning, I believe it is a chance to postpone that second death just a little bit longer.
Well said. The two deaths gives me something macabre to think about today đł
Here are some of the various projects/repos she had. There are some useful projects, some whimsical projects, and other neat stuff in there.
Someone in the tech community. Super easy to Google.
I googled and I still donât understand the notoriety.
She mostly grew up in notoriety in the golang and k8s community. I will not do a full eulogy, this is not the place, nor am i well placed for that.
But despite all the disagreements we may have with her, Nòva was a genuinely nice person to have in our community, pushing forward in interesting front, saying things that needed to be said, and in general someone a lot of us appreciated having in our communities.
Thanks for the note!
No, they are not. Now, Googling her just results in a lot of people expressing sadness over her passing. I do not want to intrude on anyoneâs grief here, but Iâd never heard of her before and Iâve not been able to find any solid info about her life or work, just as @4ad below says.
@colindean above said she did the best talk of FOSDEM 2023. I was at that event, but Iâd never heard of her, nobody mentioned this talk, and Colin does not link it so I donât know for sure what talk it was.
Iâve googled that too â this is way more work than I should have to do, frankly â and I think it might be this one, but the blurb is fairly content-free and tells me nothing useful.
But the talk is also mentioned here and that gives a little context.
Apparently she ran Hachyderm. I hadnât heard of that, either. Apparently it is a Mastodon instance â I see little to distinguish these, TBH, and while Iâm on Mastodon/Fediverse, I find it little to no use. But David Calvert said:
Thatâs more info than anywhere else in this thread.
Hachyderm is apparently
She mightnât have been well-known amongst journos, but she was well known amongst developers and ops/infrastructure engineers.
Searching for her on Google and DDG, sheâs famous enough to warrant a sidebar on Google, and her website is above the fold on both. DDG gives better results, and also includes a link to her ORA authorâs profile above the fold. Sheâs definitely very Googlable.
Hachyderm was a side-gig. The blurb also wasnât content-free: the talk was about how she managed to scale out Hachyderm, which started as a personal Mastodon instance, in the face of a massive influx of users.
The Hacyderm talk she gave at FOSDEM earlier this year was on the main track, which was wedged, which is unusual for a non-keynote talk in Jansen. She also gave a talk about the Aurae low-level container runtime on the Rust track.
We should all remember that our lack of awareness of somebody does not mean that theyâre not well known.
I guess Cunninghamâs Law was right after all.
Is it my imagination or are the python people simply stuck in the realm of single processing computing? Go has been able to do multi-core for like itâs whole existence. Same thing with rust, nim C. C. Sharp, I just never see why Python is such a popular language. Perhaps itâs just the good marketing.
The thing to remember is Pythonâs age and heritage. Itâs older than Java, and comes from the Unix tradition where if you wanted to do more than one thing at a time you forked a separate process for it.
So thatâs what Python did, and then Java happened. And Java did threading (because it was originally designed to run in environments that couldnât support true process-based multitasking), and Java marketing hype pushed threading as the one true way to do things, and suddenly threading was a thing people were demanding.
So Python added threading. But, at that stage of its history, one of Pythonâs big draws was the ease with which it could wrap around existing popular C libraries. And basically none of those wrappers were thread-safe, so Python had to make a tough decision/
The decision was to preserve as much backwards compatibility as possible, via the GIL. Which, at the time, seemed a reasonable tradeoff: the GIL primarily hurts you if your workload is pure Python and CPU-bound, and at that time most of what people wanted threading for was IO-bound workloads like network daemons and services. Plus, most people didnât have true multi-processor/multi-core hardware, and even if they did their operating system might not be able to use it (anyone remember how long it took to land Linux SMP, for example?).
Now, decades later, we all have multi-core/multi-processor computers in our pockets, and so it looks like a less reasonable tradeoff, but thatâs solely because of the benefit of hindsight.
Also, you mention Go, Rust, Nim and C# as examples of languages which somehow magically had the foresight to get it right⌠you might want to check when those languages first appeared, and compare to when Python did (and when Python had to make its threading choices).
You realise that Python is much older than Go, Rust, and Nim, right?
The GIL isnât an issue inherent to Python, but to the CPython C API. It exists because to make it easier for those writing C extensions that are not guaranteed to be threadsafe out of the box to be treated as threadsafe.
Go partly solved this issue by creating a largely isolated ecosystem. When you do need to reach to the outside world, the inevitable use of CGo is painful. Same for C#: .NET is its own isolated ecosystem. Rust has a complicated type system to cope with this, and the
unsafe
escape hatch where you really need to know what youâre doing.Pythonâs âmarketingâ is that itâs a pleasant and approachable language. The real shame is that Python didnât starting out with a C API more like that of Lua or Tcl, but Lua is a younger language, and only got itâs current API in 4.0 when it was much less popular and breaking compatibility was thus less of an issue. I canât say much about Tcl historically except note on the current state of its C API.
The gap in your knowledge is a lack of a historical perspective. Theyâre not âstuck in the realm of single processingâ, itâs simply that nobody particularly wants to break the C API, and a lot of effort has been put into avoiding doing so in the past, but things are finally starting to give.
What bar needs to be cleared for a programming language to deserve existing? Code written in Python has been used to earn Nobel Prizes in the sciences.
So has code written in FORTRAN77, but that doesnât mean that Iâd want to inflict the experience of writing F77 code on someone.
Thatâs a pretty bad argument. Code written in Python has also been used to commit atrocities.
Iâd like to know more about these atrocities.
Many people have great responses, but I just wanted to mention another aspect. When did you first own a computer that could execute two threads simultaneously?
I think I first had a hyper threading processor before I had multiple cores. That would then be the Pentium 4, released in 2002. That would make it 1/3 into the lifetime of Python up until now.
Another other thing that I think could be important is that threads were cheap on windows and processes were expensive. In Unix, a thread was not that much less expensive than a process. I remember the feeling of âthreads are for Windows where they canât handle many processes and canât spawn them quicklyâ.
POSIX threads were also only standardized in 1995. To decide on a cross platform implementation of threading, when windows didnât support POSIX threads natively, would have been tough to do. Especially for a feature that wasnât super useful for performance.
IIRC, theyâre still expensive and require something like 1MB of memory per process at minimum.
Itâs much less than that. They typically require something like 2-8 MiB of address space for the stack, but that stack is lazily committed so youâre not consuming real memory unless you actually use all of the stack space. Beyond that, you typically have a few KiBs of kernel state for the thread (including register save area, which can be quite large with AVX or SVE), userspace thread structures, and userspace TLS. These rarely add up to more than a few pages.
Perhaps itâs a nice pairing of syntax and semantics, on top of a mostly-sane standard library, thatâs been around since 1991.
While I donât disagree with the general message here, this sentence stuck in my throat:
âThe conceptual model of HTTP is also simple, in that you can basically view it as an RPC system.â
Ugh. Thatâs exactly what HTTP is not, conceptually or otherwise.
I donât want to say that HTTP is a good RPC system or that it has all of the features of a proper one, but at a high level I think what a lot of people want out of their RPC is âmake fixed call, get results and/or statusâ. HTTP requests with JSON payloads work pretty well for this and they donât require, say, a connection setup phase the way a SMTP-like or IMAP-like protocol might have. At a low level HTTP can have keepalives and connection reuse and so on, but I think that tends to be either hidden away in the HTTP library or optional.
(Iâm the author of the original, linked-to entry.)
In what way is HTTP â or, at least, HTTP POST â not RPC?
REST certainly isnât RPC, sure, but REST is an abstraction layer above HTTP.
The words are all messed up at this point, but RPC traditionally meant mechanisms like âprocedure namingâ and âmarshal arguments and return valuesâ. Itâs designed to make remote procedure calls as convenient as local ones with respect to particular programming languages.
So Iâd say HTTP isnât RPC because itâs not designed for, or convenient for, that purpose.
You can make it do such things, but it takes extra work, and you also lose things like HTTP proxy support (middleboxes).
If HTTP were RPC, then you wouldnât have additional protocols like JSON-RPC tunneled inside HTTP. JSON-RPC specifies how your arguments and return values are marshaled.
If HTTP were RPC, you wouldnât have to say âHTTP POSTâ. Middleboxes understand HTTP verbs; they often donât understand your custom protocol inside HTTP. The network isnât just about the end points.
Likewise, TCP/IP isnât a protocol for hypertext, although you can use it that way. You have another layer with more semantics.
Ah, okay, Iâm definitely using a weaker definition of RPC than what youâre describing here.
I get the reluctance but I still think itâs somewhat semantic from the serverâs perspective:
To me, HTTP is a somewhat specialized kind of RPC (with specified caching and method encoding). We can of course build other kinds of RPCs on top of any RPC too.
We can draw the line elsewhere, but at the very least HTTP is very close to being an RPC. :)
I suppose the idea of âHTTP is RPCâ takes a minimalist definition of both termsâ RPC as in âit invokes procedures remotelyâ, and HTTP as in âa well-supported presentation layerâ.
Agreed. HTTP is definitely an RPC system. It even has verbs!
I mean Whois is definitely an RPC system: it has a verb! Sure, itâs implicit, but still!
I think you need to allow arbitrary verbs to be RPC :P
In that HTTP is all about manipulating a large set of resources (nouns) with a very small set of fixed commands (verbs), and there are no remote procedures at a conceptual level at all.
Right. As I mentioned in a sibling comment, I think Iâm using a weaker definition of RPC than what youâre describing here. For me â and I think for most developers in this day and age â RPC is anything which is synchronous and follows request-response semantics. By this definition, all HTTP operations qualify. I understand this is not the original meaning.
Fair enough. Thanks for the qualification and clarification đ
Generics do take away probably 30% of my complaints with go. No sum types is still a big pain for me, theyâre just how I naturally model things. Iâve now used Go at work for 2 jobs in a row, and I legitimately donât like it (in a âmehâ way), but I am also completely productive in it. So Iâve really taken the stance that, minus some outlandish edge cases, language isnât all that important.
Like, writing a for loop vs using
map
feels really annoying at first, but the difference ends up being pretty superficial in the long run. I do not buy at all that switching to Haskell would drastically change my daily life as a programmer. And I literally love functional programming.One other thing Iâd really like to see in Go is explicit interface conformance, i.e.
type MyThing struct implements MyInterface
. I know that defeats the whole purpose of implicit interfaces, which has other benefits (though they are lost on me), but at least make it optional. I always want to just look at something and see what it implements.Thereâs a hack to do it: either before or after the methods, add
If you write that first, the compiler will actually give you the steps, though just one at a time (e.g. missing method X, method X should have signature so and so, missing method Y, method Y should have signature so and so)
The âvar _ Ifaceâ should make it reasonably easy to find as well.
The lack of sum types is probably Goâs original sin. It left the language with nil, a clumsy way of approximating enumerations, and an error type thatâs gradually mutated into effectively a kind of checked except that you couldnât even check until 1.16, and now itâs as heavyweight as escape continuations anyway, and less convenient.
Always having a zero value interacts poorly with sum types. Whatâs the zero value of int | string?
Ha! Fun question. You canât let the zero value be nil, or nil-ish â that would defeat the purpose of the sum type in the first place. And I suspect it would be infeasible to prevent the construction of zero-value sum types altogether â such a constraint would require an enormous number of language changes. I guess the only remaining option is for the zero value of a sum type to be the zero value of the first type in its type list. So the zero value of int | string would be int(0). Thatâs not particularly satisfying!
Yeah, itâs hard to retrofit onto Go as it exists now. I think you can sort of squint and imagine a version of Go where it has
undefined
and you need to be able to statically show that something is notundefined
before youâre allowed to read from it. Sovar x union{string, int}; f(x)
would be illegal at compile time becausex
isundefined
. But it starts to look more like ânot Goâ the more you think it through.Go pretty much already has the answer, in the interface extension to type sets for generic bounds: a sum type in Go would likely be relaxing the language to allow
interface { int | string }
to be used as a regular type (currently itâs only allowed for trait bounds), and adding support for type refinement & exhaustiveness to type switches.This means the zero value would be the nil interface.
Unless Go specifically removed nil interfaces & default values from such a type, but I donât see that happening given how far it would cascade through the language. Not unless the team decided to completely overhaul default values in Go 2 anyway. Which Iâd hope but would not hold my breath for.
There are a whole bunch of different types where a zero value makes little sense, and we donât even have to be talking about sum types. The fact they interact poorly by default isnât even necessarily a bad thing, and if a language designer so deemed it useful, theyâre could just allow a constructor to be nominated as the default one.
Generics solve your last problem because interfaces are type constraints so you can use a function with an empty body to assert to the compiler which interfaces you intend a type to implement.
Golang will soon be as bloated as any other language that makes bold claims from the start and then spends itâs later years backsliding to try and draw in itâs critics.
I certainly have that concern too. However, from what Iâve seen, the Go team continues to be judicious and cautious in its choice of what to include. The only language change to speak of has been the addition of generics in 1.18. All other changes are in the standard library and the tooling, which as far as I can tell just keep getting better. It doesnât have the same design-by-crowd/committee feeling as Python has had in recent years.
This is an odd criticism of Go in general and this coroutine proposal specifically, I think. Itâs proposing a standard library package which happens to lean on runtime support for performance reasons only. Go has an HTTP server in its standard library. Being a batteries-included language seems to be out of favour at present, but this would seem to be an example of Go (quite correctly, imho) swimming against the tide and including batteries anyway.
Iâm not sure what theyâve backslid on. People bring up generics a lot, but prior to the successful generics design, the Go FAQ had said:
for what, a decade?
Full disclosure, I donât think Go is a good language. But I feel like theyâve been remarkably consistent on scope and feature creep.
Yeah, itâs kind of silly for Goâs critics to claim that Go is a bloated language when the only real piece of bloat that has been added has been generics and its critics positively screamed for that for over a decade.
The critics who are concerned that Go is becoming bloated, and the critics who screamed for generics, are different people.
(A lot of social phenomena make a lot more sense when you consider that what looks like one group from the outside is actually several groups, each with different thoughts and motivations.)
I remember when Goâs critics were arguing that its simplicity claims were easy to make as it was a new language, but âgive it 10 years and it will be as bloated as Java/Python/C++/etcâ, well it has been 14 years since Go debuted and it remains pretty bloat-free (generics is the only real bit of bloat added to the language, and that was positively demanded by Goâs critics). Itâs nice to see that people are still making this same argument 14 years later. :)
This is hardly bloat. Itâs quite close to Luaâs asymmetric coroutines and Pythonâs (synchronous) yield statement, which are both solid designs with minimal overhead.
This is a new package in the standard library, not a language feature.
Contrariwise, it seems they are doing an admirable (if quite slow) job of growing their language. I look forward to the addition of macros, inheritance, gradual typing, and unrestricted compile-time computation.
I donât know â Go goes against almost everything in that absolutely great talk. A core tenet of which is that one should be able to write a library that can seamlessly extend a language. Go has real trouble around it with an over reliance on built-ins.
Itâs no accident that Guy Steele worked on Java and later on Scheme (among others). Scheme is a more niche language and while the above core tenet definitely well-applies to that language, I would highlight Java over Go in this this gradual growth regard, given its longer life and extensive use, and if anything, thatâs its core strategy: last movers advantage. The team really well evaluates which language features are deemed âsuccessfulâ after they were tried out by more experimenting PLs.
The coroutine library described in the article is a library.
I think you have this backwards. He worked on scheme in the 70s and Java was created in the 90s. Not exactly sure when Steele got involved in Java though. I know his big contribution was generics, but I imagine you have to do some work before you get invited to do something so major.
His contribution was the Java Language Specification, among other things. He was one of the original team of 4 (James Gosling, Guy Steele, Bill Joy, and maybe Arthur van Hoff, the namesake of Javaâs AWT package a la âArthur Wants Toâ). Heâs still at Sun/Oracle Labs (his office was right next to mine).
Heâs also known for Lambda The Ultimate (LTU), a series of papers that he published in the 70s, I think. (Thereâs a website by that name, inspired by those papers, and focused on PL topics.) And a bunch of other things heâs been involved with over the years at and around MIT. Including square dancing.
until recently with some significant breakthrough, his name was still on the paper defining how to cast a float to a string precisely (minimal length round trip safe conversion).
To be fair. This technique was probably known before hand, and the co-author, Dyvbig iirc, probably did more work than him. But still.
Oh this algorithm is every where. Like nearly all libc.
Ah! Thatâs interesting! Wikipedia only lists Gosling as the designer. I double checked the wiki page for Java before posting, but I guess it doesnât tell the whole story. Thank you for the clarification!
Oh, didnât realize Scheme is that old of a language! He has made quite some contributions, having been also on the ECMAScript committee.
Yeah, he also was one of the original authors of emacs. Pretty crazy career when you think about it!
I guess the sarcasm didnât quite come throughâŚ
That said, Iâm actually somewhat curiousânot really knowing either language particularly wellâin what respects java is more expressive and orthogonal than go. Both added generics after their initial release, are garbage-collected (though java is much better at it), have some semblance of first-class functions, have some semblance of generic interfaces, and have some cordoned-off low-level primitives. Both are sufficiently expressive and capable that most of their infrastructure is written in itself (contrast with, say, python); hotspot happens to be written in c++, but this seems more a consequence of historical factors, and istr cliff click said that if he were writing hotspot today, he would write it in java. Java has inheritance and exceptions, where go does not; are there other major differences?
Go has goroutines which Java is soon to get. Go has value types and value/pointer distinction, which Java is maybe getting at some point
The biggest difference is that Java (in a typical implementation) is a fairly dynamic language, while Go is a fairly static one. Dynamically loading classes into your process is the Java way. Java is open-world, Go is closed-world.
I feel the last property is actually the defining distinction, as language per se doesnât matter that much. I do expect Go & Java to converge to more-or-less the same language with two different surface syntaxes.
Is Java actually going to get this soon? I feel like Iâve been hearing itâs just around the corner for like 5-10 years.
I donât follow too closely, but my understanding is that green threads (the current reincarnation of) are fairly recent (work started 2017), and are almost there (you can already use them, they are implemented, but not yet stabilized).
Work on value types I think started in 2014, and it seems to me that thereâs no end in sight.
The green threads work started a lot earlier than 2017. Not sure when it got staffed in earnest, but the R&D had been going on for a while before I left in 2015.
I think it goes in this year. Iâm not a java guy, but I think this is the final JEP.
https://openjdk.org/jeps/444
Interesting. Where can I read more about the Java equivalent of goroutines?
Itâs called the Loom project. It is already available in preview for a few Java versions, so you can also play with it. The cool thing about it is that it uses the same APIs as the existing Thread library, so in many cases you can just change a single line to make use of it.
https://jdk.java.net/loom/
I canât tell if the sarcasm here is âyou think Go is becoming bloated very quicklyâ or âGo is never going to add these features (and thatâs a bad thing)ââŚ
One thing that I think a lot of people forget about is directly booting a kernel with your bolted on executable. They tend to be very small and very effective. Theyâre just a little bit hard to make.
Historical note: this is basically what all DOS games did, IIRC.
Is this referring to that DOS/4GW thing that games seemed to use? Or something else entirely?
Kind of the opposite. That was what was called a âdos extenderâ which basically was a combination of an extended init that gets the CPU in 32bit protected mode (which could coordinate with other popular software that may interfere with doing so the easy way), a small runtime to call into v86 mode so that you could still use DOS for file access and call the VGA BIOS, and some library code to talk to it. DOS/4G was a standalone one that was pretty expensive, so wasnât very common, but DOS/4GW was the same product bundled in with Watcom C++ and was everywhere.
Iâm failing to understand what this has to do with the article? The submission is about how Firecracker is designed for the kind of workload that might work for, but is a very poor fit for the dev environment use case.
I think the main thought that I had was around micro VMs. It might have been a bit longitudinal in the sense that itâs not a build agent, but I am betting that a micro VM would be another valid use case for a very fast build server.
You mean unikernels?
Good! Iâve loathed the .egg format for so very long. One day, hopefully not so far in the future, setuptools and everything associated with it will, with any luck, shrivel down to something much smaller and much more sane. Preferably, itâll just go away completely.
Thatâs interesting, because thereâs a fair amount of Erlang used in industry â it was created for telephone switching systems, not as an academic exercise. CouchDB is mostly written in it. Is Kafka in Erlang or am I misremembering?
As to your main point, Iâm not a Lisper, and to me the quotes you gave tend to reflect my feelings: stuff that once made Lisp special is widely available in other languages, the cons cell is a pretty crude data structure with terrible performance, and while macros are nice if not overused, theyâre not worth the tradeoff of making the language syntax so primitive. But I donât speak from a position of any great experience, having only toyed with Lisp.
Lisp has very little to do with cons cells.
Can you elaborate? Arenât lists the primary data structure, in addition to the representation of code? And much of the Lisp code Iâve seen makes use of the ability to efficiently replace or reuse the tail portion of a list. That seems to practically mandate the use of linked lists â you can implement lists as vectors but that would make those clever recursive algorithms do an insane amount of copying, right?
No. Most lisp code uses structures and arrays where appropriate, same as any other language. Iâm not sure what lisp code youâve been looking at, so I canât attest to that. The primordial LISP had no other data structures, it is true, but that has very little to do with what we would recognise as lisp today.
I think it stems mostly from how Lisp is taught (if itâs taught at all). I recall back in college when taking a class on Lisp it was all about the lists; no other data structure was mentioned at all.
Thatâs a popular misconception, but in reality Common Lisp, Scheme, and Clojure have arrays/vectors, hashtables, structures, objects/classes, and a whole type system.
I donât know what Lisp code youâve looked at, but in real projects, like StumpWM or the Nyxt browser or practically any other project, lists typically donât play a big role.
Unfortunately, every half-assed toy language using s-expressions gets called âa Lispâ, so thereâs a lot of misinformation out there.
Clojure and Fennel and possibly some other things donât used linked lists as the primary data structure. Both use some kind of array, afaik (Iâve never properly learned Clojure, alas). How this actually works under the hood in terms of homoiconic representation I am not qualified to describe, but in practice you do code generation stuff via macros anyway, which work basically the same as always.
As I said above, this is a divisive issue for some people, but Iâd still call them both Lispâs.
Depends a bit on the personâs perspective. Iâve seen some people get absolutely vitriolic at Clojure and Fennel for ditching linked lists as the primary structure. I personally agree with you, but apparently it makes enough of a difference for some people that itâs a hill worth dying on.
You might be thinking of RabbitMQ. Kafka is on the JVM.
I donât think Kafka is, but CouchDB certainly is and, famously, WhatsApp. Itâs still not so common but not unheard of, especially now in the age of Kubernetes, although ElixĂr seems reasonably popular. Either way I donât think most people know much about its history, they just sort of bucketize it as a functional language and whatever biases they have about them
I never actually wrote much Erlang â I only even mentioned it in that interview because the founder mentioned belonging to some Erlang group on his LinkedIn. It turned out to have been something from his first startup, which failed in a bad way, and I think he overcorrected with regard to his attitude toward FP. He was a jerk in any case
edit: looks like you might be thinking of RabbitMQ? https://en.wikipedia.org/wiki/RabbitMQ
Kafka is a JVM project. Itâs written in Java and Scala.
Itâs quite possible youâre thinking of Riak, which was implemented in Erlang, though the two are very different beasts.
I would like to have this back.
Very soon. WebAuthn & Passkeys
I think you complete misunderstand my comment.
I want this back, because WebAuthn is far to complex and adds the problem that the Website and the backend has to implement the authentication. With KEYGEN all about the keys is handled by the browser. The authentication check then can be done by the httpd.
Yes I know there are some issues with the UI and other issues on implementation side. But this is nothing conceptional and can be improved.
To your other comment about storing the credential on separate device: What stops a browser from doing the same thing with keys generated by KEYGEN?
Nothing, in fact browsers support that (smartcards)
All Iâve seen from the WebAuthn world has made it seem like an excellent way to lock yourself into either Googleâs or Appleâs ecosystem as you he two companies demand to control all your online accounts. Where does the person who uses Android on their phone, macOS on their laptop and Linux on their desktop fit in to this brave new world?
You can store credentials on a device that speaks USB or Bluetooth pr NFC. No need to store the material on your computing device.
If only! At $WORK, we use WebAuthn for SSO, and we use YubiKeys as the second factor. We explicitly set âusbâ as the only allowed transport because we require people to use their YubiKeys to generate their WebAuthn token. However, neither Chrome nor Safari respect this and will instead try to get the user to register a passkey instead, which naturally wonât work. And the token registration UIs in both are actively hostile to using any methods other than passkeys. Firefox is at least better in this regard, but possibly only because its WebAuthn support is less extensive.
Right, but thatâs now what any of the big players are making, even if itâs technically possible.
And Iâm not going to be bringing around a dedicated Bluetooth or USB key device. And I doubt my iPhone would support it even if I did.
The whole âletâs get rid of passwordsâ WebAuthN thing seems like a huge lock-in opportunity for the huge companies and nothing more IMO.
I get your scepticism, but imho it doesnât sound too justified to me.
WebAuthn: You can already buy a Yubikey that does NFC and works for iPhone.
PassKeys I donât have experience with, but I know there are open implementations that will help avoid lock-in.
Alright but Iâm not going to be using Yubikeys. So how do I sync my passkeys between my phone and desktop, so that I can log in to any account without the involvement of the other device?
Nothing in WebAuthn adds a dependency on anything other than your computer. On Windows, the private keys are stored in the TPM, on macOS theyâre stored in the Secure Element, and on Android devices theyâre stored in whatever the platform provides (a TrustZone enclave in the worst case, a separate hardware root of trust in the best case). All of these are defaults and, as far as Iâm aware, all support using an external U2F device as well. At no point does Apple or Google have access to any my WebAuthn private keys. On other platforms, itâs up to the platform how it stores the keys, but I believe the TPM is pretty well supported on Linux.
Aaaaand by what mechanism are the keys synced between my iPhone and my Linux desktop?
I need to be able to create an account on my Linux desktop (which doesnât have a TPM, by the way) and then log in to that account with my iPhone (without the involvement of the desktop at the time of login). I also need to be able to create an account on my iPhone and then log in to that account with my desktop (without the involvement on my phone at the time of login). This is no problem using passwords and password managers. My understanding is that itâs impossible with WebAuthn.
They arenât. By design, there is no mechanism to remove the keys from secure storage. If there were, an OS compromise could exfiltrate all of your keys instantly. You create a key on one device and use that to authorise the next device. Alternatively, you use a U2F device and move it between the two machines (I believe iOS support U2F devices over NFC, your Linux machine definitely supports them over USB).
Are you sure? Most vaguely recent motherboards have one (at least an FTPM in the CPU). Without one, thereâs no good way of protecting LUKS keys, so that might be something to look for in your next upgrade.
You seem very interested in pushing this U2F device thing. I donât know how many times I need to say Iâm uninterested.
And if I canât create an account on one device and then log in on another device without the first device involved, this is not something for me. What do I do if I make an account on my phone, happen to not log in to it on anything other than my phone, but then my phone breaks and I need to log in on my desktop? Is that just ⌠not supported anymore?
And why should I think Appleâs implementation will even allow me to authorize my Linux machine? Is that something which falls naturally out of the standard or has Apple publicly committed to it or are you just hoping theyâll be nice?
I just know my (rarely used) Windows install doesnât let me upgrade to 11 due to missing TPM. Also, older hardware is a thing.
I also donât have a need for LUKS.
You need to store keys somewhere. You have three choices:
Thatâs what WebAuthn recovery codes are for. Store them somewhere safe and offline.
I have no idea what this even means. Apple, Google, Microsoft, and Mozilla implement the client portion of WebAuthn. They have no control over which other devices any WebAuthn provider lets you use, just as a recommendation to use a strong password in Safari has no impact if you reset the password in Chrome or Edge.
You seem to think WebAuthn is something completely different to what is actually is. I canât really help unless you explain what you think it is so that I can understand how you get to the claims youâre making.
I believe Windows 11 requires a TPM 2.0 implementation. TPM 1.x is fine for these uses and is 14 years old at this point.
You place a lot of faith in your physical security.
I have tried to read up on WebAuthn actually, and have never found out how they intend transfer of identities between devices to work. It leads me to believe that youâre either supposed to have one device (the phone) be the device which authenticates (similar to how 2FA systems work today), or sync keys using some mechanism thatâs not standardised. But it sounds like you believe thereâs another mechanism; can you explain or link to some documentation on how thatâs supposed to work?
Nothing stops you from having multiple keys with a single account, IIRC. You could have one device initially authorize you on another system and then make a new key for the other device.
You havenât read that because it is out of scope for WebAuthn. WebAuthn provides a mechanism for permitting a remote device to attest to its userâs identity. It is up to the implementer of the server-side part to provide a mechanism (beyond recovery codes) to add a second device. The normal way of doing this is to use one device to enrol another. For example, you try to log in on your computer, it shows a 2-3 digit number, then you log in on your phone and approve, now both devices are authorised.
If your objection to WebAuthn is that the higher-level flows that people build on top of it have problems then you should direct your criticisms there.
Windows 11 requires TPM 2.0, So its possible to have a TPM without W11 supporting it
Honestly, Iâm not sure it would be that usable by modern standards. I donât think anything other than RSA was widely supported, and then limited to 2048 bit key sizes, etc. It would need a lot of modernisation. I wonder if the web crypto API can provide any suitable alternatives? Not sure if it has facilities for local key storage.
The limit to RSA and 2048 bit key size is just a implementation limit. Of course this should be improved. The charming part of this is, the website donât has to interact with the key. Yes I know there are some issues with TLS client auth, but with auth optional this can improved.
This is a real pity. Hopefully the idea will come back in an adjusted form as it solves a real problem.
Exceptions are values in Python. Iâm not sure where the notion that theyâre not could come from. This is an issue is flow control. Go has one kind of escape continuation, which is triggered by the
return
statement, where as Python has two: the one triggered byreturn
and the one triggered byraise
. However, both of these handle values.I think what itâs traditionally intended by âerrors are values in Goâ is related to the way they are being handled, not produced. In languages where error escaping is done with exceptions, in this case Python, they are usually handled by type, not by value.
When you use the likes of
fmt.Errorf()
youâre minting new objects, just as you do with calling an exception typeâs constructor. The difference is that you have basic pattern matching (because thatâs what an exception handler does) on the type, allowing you to discriminate between them, which you canât do with the likes offmt.Errorf()
.OK. Iâm not sure if you disagree with me, I just tried to explain how I understood the âerrors are valuesâ concept in Go.
What about panic?
A panic is more akin to a Unix signal.
panic
unwinds the stack until arecover
â this is not the same as a signal.âErrors are just valuesâ links to a blog post that explains what that means. https://go.dev/blog/errors-are-values
I know. What I disagree with is the âUnlike Pythonâ bit.
I think youâre looking to closely at specifics, rather than the gist of it: errors are handled using the same language features as other values, unlike exceptions which are handled using dedicated language constructs. Python doesnât do
return Exception
even if it could.This is not accurate. Go tuples are an error-specific language feature in the same as way Pythonâs
except
. You canât use tuples as a general construct.Go doesnât have tuples, but it does have multiple return values. Often the last return value is an error, but thatâs not a language feature or requirement or anything, itâs just a convention. So I think the OP is accurate.
Thereâs a strong convention to use it like that, but Go lets you use it with any type you want. You could use it to return e.g. (x,y) coordinates if you wanted.
Go dropped the ball on having special-case multiple-value return instead of just single-value return with tuples and destructuring, but having âsimpleâ non-generalizable features is sort of their thing.
But even when used with errors,
if err != nil
is definitely spiritually closer toif (ret != -1)
thantry
/catch
.Go doesnât have first class tuples, but its return tuples are not specific to error handling. You can return two ints; or an int, a bool, and a float; or whatever else.
Sure, by its nature this is true, because itâs a tuple. But with non-error types you have multiple ways to return them, whereas errors are always returned using the tuple special-case. Tuples exist to return errors.
Iâm not sure what youâre saying. As a convention, people return errors as the last type in a tuple, but itâs just a convention. You can return them through global values (like C errno) or out value pointers instead if you wanted to. I have a couple of helper functions that take error pointers and add context to the thing they point at. And people return other things in tuples, like bools or pairs of ints. Itâs a historical question whether multiple return was intended for errors, but I do know that before Go 1.0, the error type was a regular type in the os package and it was only promoted to a built in when Roger Peppe (who doesnât work at Google AFAIK) proposed doing so.
Out of curiosity, I dug up the original public introduction from 2009. To my surprise, Pike made it entirely through that presentation without ever mentioning error-handling that I can find.
So, I hit the wayback machine. The very first introduction of function tuples on the website uses error returns as the use-case. This slide deck from Pikeâs Go course also introduces multiple returns with error handling.
I donât think itâs fair to say this is just a convention, it is how the designer of the language chose to introduce the feature to people for the first time.
The distinction worth making here is not that âerrors are valuesâ, that is uninteresting. Itâs true in Python. The distinction is non-local returns vs multivariate functions.
Youâre describing multiple return values as âfunction tuplesâ. I donât think this is really accurate, as those return values are always discrete. Go doesnât really have a concept of a tuple.
The thing that âerrors are valuesâ tries to communicate isnât any detail about the specific implementation of the error type, but rather that errors are not fundamentally different than other types like ints or structs or whatever, and that error handling can and should use the same language constructs as normal programming.
In Python, exceptions are values, but theyâre not just values; theyâre values that interact with the exception-handling mechanism, which does things to and with them (unlike
return
, which doesnât care what kind of value you give it, and doesnât modify that value).I thought this was an interesting compare-and-contrast of Python package management with Node and C#. Being a relative newbie to Python packaging, Iâm never 100% sure if something is confusing because I havenât invested the time to learn it yet, or if itâs confusing because itâs actually more complex than it needs to be. The author echos some frustrations Iâve personally felt but couldnât quite articulate myself.
The biggest surprise to me was that the author argued against virtualenvs! Iâve always assumed that venvs were a necessary evil, and that the way to address their rough edges was to use a tool that manages them for you (like pipenv or Poetry). This blog article is the first place Iâve heard of PDM or PEP 582 â my inclination is to go with the crowd and stick with Poetry (or any more-popular tool that displaces it), but I wish luck to everyone involved in replacing the venv model with something simpler.
They currently are a necessary evil, because something like PEP 582 requires a bunch of buy-in that virtual environments donât. They were a solution to a problem that didnât require any action from anyone but the user.
Thatâs a very good description of what went wrong with Python packaging.
I donât disagree! Mind you, virtualenv was a revelation back in the day. Itâs just a pity the core team have a history of what is at best benign neglect when it comes to packaging, which lead to the setuptools debacle, and how it was left to rot for years after PJE became a motivational speaker. A lot of the problems with the Python ecosystem can be traced to that abandonment.
Yeah, I totally agree.