1,491 karma · joined July 25, 2020
The estimate of "The Internet" connecting 800,000 computers is probably also pretty surgically date-identifying (at least to isolate 1992 to 1998 given how fast it was growing at the time, though estimation error might cause a little trouble!). For example, https://web.mit.edu/people/mkgray/net/internet-growth-summar... also suggests 1994 (although that estimate was 0.6 million) while 1992 would be more like 200,000 although as per my scare quotes (and that MIT link) "The Internet" was also a somewhat vague term at the time. And by 1998 it was surely over 10 million which makes the @karel-3d quite likely incorrect, although who knows - maybe that's when the EFF first put it up on their web site?
EDIT: I mostly think it matters since observations that might have seemed quite prescient in 1992 (like also-Mormon Orson Scott Card's even more prescient ideas in 1985 Ender's Game with Locke & Demosthenes political chat personas based on 1980s BBS/UUCP network activity) were very much things everyone was saying by 1998.
So, sure, this "4th dimension" (for normals) might be as simple as "candelas" - truly orthogonal, but one does hear an awful lot about "ambient" or "candela contrastive" (a term I just made up) kinds of effects. (EDIT: e.g. in color calibration of projectors in dark rooms vs. living rooms, for example, but I'm sure there are many.) I am just one person, but it feels like candela brightness matters for color perception. So, maybe luminous intensity is not actually exactly orthogonal. Maybe this is all covered in the 1931 CIE documents, though.
Unmentioned so far is that defaults for max live memory maps are usually much higher than defaults for max open files. So, if you are careful about closing files after mapping, you can usually get more "range" before having to move from OS/distro defaults. (E.g. for `program foo*`-style work where you want to keep the foo open for some reason, like binding them to many read-only NumPy array variables.)
If it helps anyone explain the SkiFire point any better, I like to analogize it to an I-bar cursor vs. a block cursor for text entry. An I-bar is unambiguously "between characters" while a block cursor is not. So, there are questions that arise for block cursors that basically never arise for I-bar cursors. When just looking at an integer like 2 or 3, there is no cursor at all. So, we must instead rely on names/conventions/assumptions with their attendant issues.
To be clear, I liked the SkiFire explanation, but having multiple ways to describe/think about a problem is usually helpful.
For many years (decades?) now, I've been using "index" for 0-based and "number" for 1-based as in "column index" for a C/Python style [ix] vs. "column number" for a shell/awk/etc. style $1 $2. Not sure this is the best terminology, but it is nice to have something consistent. E.g., "offset" for 0-based indices means "off" and even the letter "o" in some case becomes "the zero of some range". So, "offset" might be better than "index" for 0-based.
Maybe people should instead talk about how they use D or what they'd like to see added to D? In an attempt to be the change one wants to see, I'd say named arguments are a real win and there seem to be some stalled proposals for that in D last I checked.
FWIW, I think "standing out" due to paradigm commitment is mostly downstream of "xyz-purity => fewer ways to do things => have to think/work more within the constraints given". This then begs various other important questions, of course.. E.g., do said constraints actually buy users things of value overcoming their costs, and if so for what user subpopulations? Most adoption is just hype-driven, though. Not claiming you said otherwise, but I also don't think the kind of standing out you're talking about correlates so well to marketing. E.g., browsers marketed Javascript (which few praised for its PLang properties in early versions).
Some might appreciate a concrete instance of this advice inline here. For `foo.nim`, you can just add a `foo.nim.cfg`:
@if gcc:
gcc.exe = "musl-gcc"
gcc.linkerexe = "musl-gcc"
passL = "-static -s" @end
There is also a "NimScript" syntax you could use a `foo.nims`: if defined gcc: # nim.cfg runs faster than NimScript
switch "gcc.exe" , "musl-gcc"
switch "gcc.linkerexe", "musl-gcc"
switch "passL" , "-static -s"Unsaid was that much of this project separation comes from glibc being born as (and probably still being) a "portable libc with extra GNU-ish features", not a Linux-specific thing.
Honestly, some of this pain might have been avoided had the Bell Labs guys made two libraries - the syscall interface part of `libc`, called say `libos`, and the more articulated language run-time (string/buffered IO/etc./etc) the actual `libc`. Then the kernel could "easily" ship with libos and libc's could vary. To even realize this might be helpful someday likely required foresight beyond reason in the mid-1970s. Then, afterwards, Makefile's and other build system stuff probably wanted to stay with "-lc" in various places and then glibc/others wanted to support that and so it goes. Integration can be hard to un-do.
Anyway, to answer grandparent, I basically never had rebuild loops in 19 years.. just emerge -uU world every day or sometimes every week. I have been running the same base system since..let's see:
qlop -tvm|h1
2007-01-18T19:50:33 >>> x11-base/xorg-server-1.1.1-r4: 9m23s
I have never once had to rebuild the whole system from scratch in those 19 years. (I've just rsync'd the rootfs from machine to machine as I upgraded HW and gradually rebuilt because as many others here have said, for me it wasn't about "perf of everything" or some kind of reproducible system - "more customization + perf of some things".) The upgrade from monolithic X11 to split X11 was "fun", though. /sI do engage in all sorts of package.mask/per-package use/many global use. I have my own portage/local overlay for things where I disagree with upstream. I even have an automated system to "patch" my disagreements in. E.g, I control how fast I upgrade my LLVM junk so I do it on my own timeline. Mostly I use gcc. I control that, too. Any really slow individual build, basically.
If over the decades, they ever did anything that made it look like crazy amounts of rebuilds would happen, I'd tend to wait a few days/week or so and then figure something out. If some new dependency brings in a mountain of crap, I usually figure out how to block that.
[1] https://github.com/c3lang/c3c/blob/master/test/test_suite/co...
`native-image -jar helloworld.jar helloworld` did take a whopping 17 seconds to compile, what might be the smallest possible project. That does makes me worry for iterations trying to get better perf in a context where startup overhead matters, BUT the executable it produced did run much faster - only about 1.8x slower than `tcc -run`:
97.0 +- 1.7 μs (AlreadySubtracted)Overhead
98.2 +- 2.8 μs awk '{}'</n
376.4 +- 4.4 μs tcc -run /tmp/true.c
527.9 +- 4.0 μs perl</n
686.5 +- 3.9 μs ./helloworld>/n
Perl has 2 more shared libraries for ld.so to link, but is somehow faster. So, there may still be some room for improvement, but anyway, thank you for the correction.(Also, I included 4 of the faster comparative programs to show additionally that the error bars are vaguely credible. In truth, on time shared OSes, the distributions have heavier tails than Gaussian and so a single +- is inadequate.)
--
EDIT: So, the ld.so/dynamic linking overhead was bothering me. I had to get a musl + zlib build environment going, but I did after a few minutes and then found this result with a fully statically linked binary executable:
398.2 +- 4.2 μs ./helloworld-sta>/n
(I should have noted earlier that /n -> /dev/null is just a convenience symlink I put on all my systems. Also, this is all on Linux 6.18.2 and the same CPU as before.)Also, only around 4.2 MiB of RSS compared to ~1.8 MiB for dash & awk. So, 2.4x the space and only ~4X the time of static awk & dash. That might sound like criticism, but those are usually the efficiency champs. The binary size is kind of hefty (~2x like the RAM use):
$ size *sta
text data bss dec hex filename
2856644 3486552 3184 6346380 60d68c helloworld-sta
So, I guess, in 2026, Java start-up overhead is pretty acceptable. I hope that these "real numbers" can maybe add some precision to the discussion. Someone saying "mere milliseconds" just does not mean as much to me as 400 +- 4 microseconds, and perhaps there are others like me.graalvm is literally 500x more overhead than a statically linked dash script.
Maybe not an issue for terminal UIs, but the article mentions both TUIs and CLI tools. A lot of people use CLI tools with a shell. As soon as you do `for file in *.c; do tool "$file"; done` (as a simple example), pure overhead on the order of even 10s of ms becomes noticeable. This is not theoretical. I recently had this trouble with python3, but I didn't want to rewrite all my f-strings into python2. So, it does arise in practice. (At least in the practice of some.)
$ tim "awk '{}'</n" 'tcc -run /tmp/true.c' 'perl</n' 'py2</n' 'py3</n' 'java -jar helloworld.jar>/n'
97.5 +- 1.5 μs (AlreadySubtracted)static dash Overhead
94.9 +- 3.2 μs awk '{}'</n
376.7 +- 4.6 μs tcc -run /tmp/true.c
525.3 +- 2.7 μs perl</n
3627.7 +- 6.0 μs py2</n
6803 +- 11 μs py3</n
42809 +- 71 μs java -jar helloworld.jar>/n
Also, probably there is some way to tune this, but it used over 128 MiB of RSS.[1]: https://github.com/jarirajari/helloworld [2]: https://github.com/c-blake/bu/blob/main/doc/tim.md
For example, in Nim, at the compiler CLI tool level, there is opt-in/opt-out via the `--mm=whatever` flag, but, at the syntax level, Nim has both `ref T` and `ptr T` on equal syntactic footing . But then in the stdlib, `ref` types (really things derived from `seq[T]`) are used much more (since it's so convenient). Meanwhile, runtimes are often deployment properties. If every Linux distro had their libc link against -lgc for Boehm, people might say "C is a GC'd language on Linux". Minimal CRTs vary across userspaces and OS kernel/userspace deployment.. "What you can rely on/assume", I suspect the thrust behind "optionality", just varies with context.
Similar binding vagueness between properties (good, bad, ugly) of a language's '"main" compiler' and a 'language itself' and 'its "std"lib' and "common" runtimes/usage happen all the time (e.g. "object-oriented", often diluted by the vagueness of "oriented"). That doesn't even bring in "use by common dependencies" which is an almost independent axis/dimension and starts to relate to coordination problems of "What should even be in a 'std'-lib or any lib, anyway?".
I suspect this rule is trying to make the adjective "GC'd" do more work in an absolute sense than it realistically can given the diversity of PLangs (sometimes not so visible considering only workaday corporate PLangs). It's not always easy to define things!
FWIW, the "catenation operator" in the Nim stdlib is ampersand `&`, not `+` which actually makes it better than most PLangs at visually disambiguating things like string (or other dynamic array, `seq[T]` in Nim) concatenation from arithmetic. So, `a&b` means `b` concatenated onto the end of `a` while `a+b` is the more usual commutative operation (i.e. same as `b+a`). Commutativity is not enforced by the basic dispatch on `+`, though such might be add-able as a compiler plugin.
Mostly, it's just a very flexible compiler / system.. like a static Lisp with a standard surface syntax closer to Python with a lot of parentheses made optional (but I think much more flexible and fluid than Python). Nim is far from perfect, but it makes programming feel like so much less boilerplate ceremony than most alternatives and also responds very well to speed/memory optimization effort.
from strutils as su import nil
echo su.split "hi there"
(You can put some parens () in there if you like, but that compiles.) So, you can do Python-style terse renames of imports with forced qualification. You just won't be able to say "hi there".(su.split) or .`su.split` or the like.You can revive that, though, with a
template suSplit(x): untyped = su.split x
echo "hi there".suSplit`
That most Nim code you see will not do this is more a cultural/popularity thing that is kind of a copy-paste/survey of dev tastes thing. It's much like people using "np" as the ident in `import numpy as np`. I was doing this renaming import before it was even widely popular, but I used capital `N` for `numpy` and have had people freak out at me for such (and yet no one freaking out at Travis for not just calling it `np` in the first place).So, it matters a little more in that this impacts how you design/demo library code/lib symbol sets and so on, but it is less of a big deal than people make it out to be. This itself is much like people pretending they are arguing about "fundamental language things", when a great deal of what they actually argue about are "common practices" or conventions. Programming language designers have precious little control over such practices.
There are over 2200 nimble packages now. Maybe not an eye-popping number, but there's still a good chance that somewhere in the json at https://github.com/nim-lang/packages you will find something interesting. There is also RosettaCode.org which has a lot of Nim example code.
This, of course, does not speak to the main point of this subthread about the founder but just to some "side ideas".
You could add a `SomeNumber` predicate to the `concept` to address that concern. `SomeNumber` is a built-in typeclass (well, in `system.nim` anyway, but there are ways to use the Nim compiler without that or do a `from system import nil` or etc.).
Unmentioned in the article is a very rare compiler/PLang superpower (available at least in Nim 1, Nim 2) - `compiles`. So, the below will print out two lines - "2\n1\n":
when compiles SomeNumber "hi": echo 1 else: echo 2
when compiles SomeNumber 1.0: echo 1 else: echo 2
Last I knew "concept refinement" for new-style concepts was still a work in progress. Anyway, I'm not sure what is the most elegant way to incorporate this extra constraint, but I think it's a mistake to think it is unincorporatable.To address your question about '+', you can define it for non-SomeNumber, but you can also define many new operators like `.+.` or `>>>` or whatever. So, it's up to your choice/judgement if the situation calls for `+` vs something else.
Anyway, this topic of "error handling scoping/locality" may be the single most cross-cutting topic across CPUs, PLangs, Databases, and operating systems (I would bin Numpy/R under Plangs+Databases as they are kind of "data languages"). Consequently, opinions can be very strong (often having this sense of "Everything hinges on this!") in all directions, but rarely take a "complete" view.
If you are interested in "fundamental, not just popularity" discussions, and it sounds like you are, I feel like the database community discussions are probably the most "refined/complete" in terms of trade-offs, but that could simply be my personal exposure, and DB people tend to ignore CPU SIMD because it's such a "recent" innovation (hahaha, Seymore Cray was doing it in the 1980s for the Cray-3 Vector SuperComputer). Anyway, just trying to help. That link to the DB Null page I gave is probably a good starting point.
Nim is Choice in many dimensions that other PLang's are insistently monosyllabic/stylistic about - gc or not or what kind, many kinds of spelling, new operator vs. overloaded old one, etc., etc., etc. Some people actually dislike choice because it allows others to choose differently and the ensuing entropy creates cognitive dissonance. Code formatters are maybe a good example of this? They may not phrase opposition as being "against choice" as explicitly as I am framing it, but I think the "My choices only, please!" sentiment is in there if they are self-aware.