Hacker Newsnew | past | comments | ask | show | jobs | submit | more addaon's commentslogin

And option-hyphen has typed one directly for even longer… wait, is AI coming for my option-semicolon too?


Option-hyphen usually produces an en dash—the em dash is on option-shift-hyphen.

The Unicode horizontal ellipsis is an abomination that doesn't belong in English prose, though.


What's wrong with the ellipsis? Ensures that it doesn't get distributed across two lines. And with a proper proportional font it looks just fine.


Yep. The right solution here is to make latitude and longitude distinct types.

The way to turn that into an even wronger solution is to create a helper just_apply(function, lat, long) that passes the arguments to the function in the (hopefully unique) order that successfully works; so flip if needed, based on function’s type signature.


> If understanding this special IMMEDIATE mode is required to understand the Forth interpreter for something as fundamental as control-flow, it seems fair to say that Forth is not a simple language. It's not just an advanced programmable RPN calculator An RPN calculator has a program counter, which makes control-flow easy to understand.

"Simple" is not a well-defined threshold but rather a continuum, so it's hard to agree or disagree with this. I think it's perfectly valid to observe that Forth is more complex than an RPN calculator, though.

But think of it this way: An RPN calculator has two types of tokens, literals and symbols. When seeing a literal, it evaluates a push of that literal to the stack. When seeing a symbol, it evaluates an immediate call to the behavior associated with that symbol.

Forth adds exactly one more concept: non-IMMEDIATE words. Everything an RPN calculator can do can be done as IMMEDIATEs in Forth. But by adding one metadata bit to the symbol table (IMMEDIATE or not), and adding a threaded call to any non-IMMEDIATE words to the output code stream, Forth gains function definition, full generic control flow support, compiler extensibility, support for embedding domain-specific languages (just IMMEDIATE words that consume the interesting tokens), and more.

I don't know if this counts as "simple" compared to C, but it surely counts as "parsimonious." It's hard to think of a more cleanly defined single semantic change that adds as much power to a language.

(And of course in C, once you understand the language understanding the runtime library is mostly about understanding runtime behavior, some macros not withstanding; but in Forth, the runtime library and the language are conflated through IMMEDIATE symbols, so this separation is much less clear; totally accept that this could be considered less "simple", although in practice most Forths have about as many pre-defined IMMEDIATE words as C has keywords.)


> Unlike most languages, Forth has two stacks.

Like Forth, Ada has two stacks. Unlike Forth, which uses two stacks to simplify the language, Ada uses two stacks to complexify the language. This generalizes to other language features.


Ada's auxiliary stack is used to permit the returning of runtime-variable-sized objects from subroutines, which is also a thing you can use the operand stack for in most Forths.


> So there must be something else fundamental in the Forth interpreter that I don't understand.

The missing bit is IMMEDIATE mode. Words can be tagged as IMMEDIATE, which means that they get executed at compile time (or parse time, for an interpreter), rather than a call to them getting compiled (executed at run time, for an interpreter). IF/ELSE/THEN are then "just" IMMEDIATE mode words -- but you can add your own. The "special sauce" is that IF compiles (easier to talk about for a compiler; generalize as needed) a conditional branch to an unknown address, and puts the address of that branch instruction (or an equivalent) on the /compile time/ data stack; THEN then looks at the address on the /compile time/ data stack and patches that instruction to branch to the correct address. Plenty of subtlety possible, but the basic primitive of IMMEDIATE mode is the key.


Ah I see, this is peeling back a few layers of obscurity about the Forth interpreter for me. Let's stick with a Forth interpreter because that seems easier to think about for me.

Are you saying that the Forth interpreter is a 2-pass interpreter? Or does the interpreter go into a special IMMEDIATE mode upon hitting the IF keyword, then it just consumes subsequent tokens without doing any dispatching, until it hits the THEN token? It sounds like nested IF-THEN-ELSE becomes tricky to handle.

How does the FORTH interpreter handle loops? Does the interpreter hit the WHILE token, goes into IMMEDIATE mode, remembers the location of the WHILE, then dispatches all the subsequent code, until it hits the REPEAT token, then branches back to the WHILE?


Oh, and because I didn't address it directly in the longer answer...

> Does the interpreter hit the WHILE token, goes into IMMEDIATE mode, remembers the location of the WHILE, then dispatches all the subsequent code, until it hits the REPEAT token, then branches back to the WHILE?

Yes. The beauty is that, in the context of a threaded code compiler (which, again, I encourage you to use as your default model for Forth, even though other options are possible), WHILE just pushes the address of the output code stream onto the compile-time stack. REPEAT expects the address to be on the compile-time stack and compiles a conditional jump to that address. This obviously and trivially provides support for nested control structures of all types; as long as the word that pushes compile-time data onto the stack is correctly paired with the word the pops it, we have stack semantics for nested control, which is exactly the expectation. So while your description is completely correct, "remembers" is almost trivial here -- "puts data on stack" is the primitive operation of remembering anything in Forth, and that's all that's needed here, no fancy data structures or look-aside buffers or anything. (Note that the compiler does require at least two non-stack data structures, the symbol table and the output code stream, but those reflect real domain complexity.)


I've actually never worked with a "pure" interpreter in Forth, only compilers of various levels of complexity. Threaded code compilers are (in my experience) by far the most common way to deal with forth -- and they are very much 2-pass. Even when used as an "interpreter," they generate (trivial, usually) machine code, then jump to it.

Consider a definition (in some ill-defined Forth variant) like

    : abs-sqr ( n -- |n^2| ) * 0 < if neg then ;
We can categorize things:

    IMMEDIATE words used here are : ( if then ;
    Normal words are * < neg
    Literals are 0
    Tokens that are not seen by the compiler directly (!) are abs-sqr, the contents of the comment, and )
So the compiler goes through one token (that it sees) at a time.

First up is `:`. `:` is an IMMEDIATE word, so the compiler just calls it now. `:` then consumes a symbol (`abs-sqr`) from the token stream so the compiler won't see it (think of calling next() on an iterator in python or equivalent), then creates a symbol table entry from that symbol to the /current compiled code output stream pointer/ -- that is, just after the last piece of code that was compiled.

Next up is `(`, since we already consumed `abs-sqr`. This is an IMMEDIATE word again -- and it just consumes tokens until one of them is exactly `)`, discarding them -- that is, it defines a comment.

Finally we get to the "easy" case, `*`. The compiler finally compiles! It looks up this symbol in the symbol table, sees that it is /not/ IMMEDIATE, and compiles a call to this address.

Now the compiler sees `0`. This is a literal token, so we don't even bother with the symbol table; we special-case code to push this value on the stack.

'<' is a non-IMMEDIATE symbol, we already know this case.

We've already discussed `if`, `neg`, and `then`. And `;` is an IMMEDIATE word that just puts a return instruction into the code stream.

Clear as mud?

There's one more step from here that's important to make, which is that the choice of what's IMMEDIATE or not is not strictly defined. Some words must be IMMEDIATE for correctness, if they interact with the compiler in interesting ways, like consuming tokens or back-patching instructions. But suppose we want to be clever... `<` works fine as a non-IMMEDIATE word. If we want to inline it, we /could/ have the compiler generalize by looking at the instructions pointed to by it, seeing how long they are (or tracking that in the symbol table), and deciding whether to inline... or we can just re-implement `<` as an immediate word that adds the appropriate instructions directly into the code stream. Combined with assembly words, this can be pretty trivially expressed, and it really changes the paradigm a bit.


> We can categorize things: > IMMEDIATE words used here are : ( if then ;

`:` normally isn’t immediate

> First up is `:`. `:` is an IMMEDIATE word, so the compiler just calls it now

`:` gets executed because the interpreter, when it isn’t compiling, goes through a loop:

  1) read a token until the next space in the input
  2) look up that token in the dictionary
    3a) if a word is found: call it
    3b) if no word is found: try interpreting the token as a number
      4a) if it can be interpreted such: push that number on the stack
      4b) if it cannot: bail out with an error message
  
So, `:` gets called in step 3a.

> Now the compiler sees `0`. This is a literal token, so we don't even bother with the symbol table; we special-case code to push this value on the stack.

As indicated above, that’s not how ‘normal’ forths work. A lookup is done for a word named `0`, and if it exists, a call to it is compiled.

Many forths had words named after small constants such as `0`, `1`, `2` or `-1` because compiling a call to a function took less memory than compiling a call to the “LIT” function and compiling the constant value.


> I've actually never worked with a "pure" interpreter in Forth, only compilers of various levels of complexity. Threaded code compilers are (in my experience) by far the most common way to deal with forth -- and they are very much 2-pass. Even when used as an "interpreter," they generate (trivial, usually) machine code, then jump to it.

Lots of good info, thank you. I don't think I will fully understand what you wrote until I implement a Forth interpreter myself.

So a side question: If most Forth "interpreters" are compilers, how does a Forth interpreter work in a Harvard architecture microprocessor (with separate memory space for data and instructions) instead of a Von Neumann architecture with a unified memory layout? In other words, in a Harvard architecture (e.g. AVR microcontrollers), the Forth compiler will live in read-only flash ROM, and it cannot generate machine code into RAM and execute it, because the data memory is not executable.


> how does a Forth interpreter work in a Harvard architecture microprocessor

You compile to "direct threaded code" in data memory; direct threaded code represents a sequence of calls as a sequence of addresses to call. So while "normal" threaded code (what Wikipedia calls "subroutine threading") would just have

    call word_a
    call word_b
    call word_c
And then executing that means jumping to the first instruction, direct threaded code would have

    &word_a
    &word_b
    &word_c
And then there's a suuuuper tiny runtime (like four of five instructions, literally) that has a "runtime instruction pointer" or whatever you want to call it, and just increments that and does an indirect call through to the next word whenever it's returned to.


No, that's not it. It's much simpler than that, yet has much deeper implications than you think. You don't see it in other languages. The closest thing would maybe be compile-time macros in Zig? But in Forth, the power it unlocks comes in its purest form, without any fluff around it.


> How is Mercury further?

Δv, the only metric that matters. Mercury is at 5.5 km/s from LEO, vs 3.6 km/s from LEO for Mars.


I'm down to around 10 lb base load. And then I hike in the desert where I carry 5 - 7 liters of water (11 - 15 lbs). And food. Saving a pound here and there is totally worth it, but there's a large part of the country where prudent hiking means the majority of your weight is water.


If saving here and there is worth it, why would a hiker carry a 300g battery? Imagine the savings from leaving that boat anchor at home along with whatever obviously non-essential gadget wants to be recharged.


I don't carry a battery, but I do carry a solar panel that weighs around 300 g. I use my phone when backpacking as a GPS receiver, map, flashlight, and eBook reader. Phone + solar panel weighs less than paperback + paper map + flashlight, gives me more flexibility for adjusting plans, and doesn't leave me out of novel after a few days.


I have tried my luck with portable solar panels, and my conclusion is that in most cases, they suck.

For a solar panel to be useful you need:

- At least a few days without access to electricity, otherwise even at max power, you won't get as much charge as a similarly sized power bank

- Good sunlight, preferably in the summer (more daylight)

- No shade, which is the opposite of what you want in hot and sunny summer days

- Correct placement for your solar panel, for example, having it hanging from your backpack will only work if you have the sun in your back

- A large enough solar panel, these tiny panels you sometimes find on power banks are useless

- Compatible devices. Solar panels have a variable power output, not all devices support it, some of them just shut down charging. Your best bet is to use a compatible power bank, but that information is not often specified. Test it beforehand!

My experience with a solar panel is from two week-long music festivals in the summer, which would be almost ideal conditions. My experience was that over the course of a week, I got about the charge equivalent of a 10Ah battery from my solar panel (rated 10W, 300g), so about half the efficiency of that gummy bear battery, for the reasons cited earlier. Maybe I could have done better with a better panel and better planning, but I'd rather have a battery, much more convenient, and cheaper too. I want to enjoy the festival, not babysit my solar panel.

So I'd say you need at least a week without electricity in the best conditions to make a solar panel worth it, preferably more, which I believe is rather uncommon.

Also, I am talking about these portable <1kg solar panels. The large solar panels that go in your car/van are another story.


We did a five day backpacking trip this summer (in Wyoming, with lots of sun) and the solar was great. Kept my wife's iPhone at 80-100% for the trip (some idiot left the usb-c cable for his phone in the car) with mostly only using it after we reached camp. Decided that with two phones we had enough redundancy to leave the paper maps behind. And we used the phone a -lot- for taking photos in addition to navigation.

I've had trips where solar would have mostly failed - 11 days of nonstop rain on the Continental divide trail in Canada, to be specific - but solar has worked for me really well in CA, UT, WY, CO, etc. the places where solar would have failed were pretty obvious in advance, too.

And it doesn't take much direct sun on a 15 or 20W panel to keep two phones and a steripen charged if you're not being crazy with the use.


To make it clear, I am not saying that solar panels don't work, of course they do. What I was questioning is using a solar panel over a power bank of the same weight.

A 20 Ah (77 Wh) power bank weight about the same as a 15W solar panel. That about 3 full (0-100%) charges on a typical smartphone. I think that would have kept your wife phone up the whole trip no problem, and no need to worry about the sun.

On a 11 day trek in the sun, yes, by all means take a solar panel. However, most people I know who do such long hikes usually have access to electricity at some point. But if it is not your case, well, you are the reason why these solar panels exist ;)


> So I'd say you need at least a week without electricity in the best conditions to make a solar panel worth it, preferably more, which I believe is rather uncommon.

That's basically my use case. I have a "15 W" panel. I can get about 5 days from my iPhone for navigation, and most of my trips are 5 - 7 days, so really it's opportunistic charging for reading on my phone after dinner. I can generally get an hour or so of reading from just hanging the panel off the back of my pack, and another two hours from setting it in the sun during my ~1 hour lunch break if it's not so hot out that nothing charges. 300 g for ~3 hours of reading at night, indefinitely, is a good trade for me.


Assuming you could afford it, would the new iPhone Air be a consideration in your ultralight base load going forward?


Potentially? I have an iPhone 15 Pro now, which I got both because it was lighter than previous equivalents, and was the first (?) with direct-to-satellite, which I definitely value. I know I can get ~5 days of navigation (but not reading) out of it, which is one of the reasons I don't take a backup battery (the solar panel isn't a single point of failure; but of course the phone still is for nav, so still need a minimal paper map and a compass). I only spend a couple weeks a year backpacking so I wouldn't choose a phone purely based on that; but if I were in the market for an update this cycle I'd consider it.

Edit: Looks like the Air is 165 g, vs 187 g for the 15 Pro; not even an ounce difference. A bit more compared to the 17 Pro (206 g); but I probably just hold on until Russia collapses into a new metastable state and we can get bulk titanium again.


The battery allows you to bring a weight-saving device; your phone.

It can - within reason - replace maps, guidebooks, emergency satellite beacons, a camera, a secondary flashlight, etc.

You can, if you want, go out with your pockets stuffed with high calorie emergency rations and no pack at all. The weight savings will be tremendous, but at a certain point the tradeoff for weight over comfort and utility becomes too silly.


Perhaps you save all the other grams, so you can 'afford' to bring the battery?


Others have already mentioned it, but once you move from pure survival to adventure/experience, carrying a way to take photos, map/GPS, read, maybe message your partner from a mountain-top, etc is part of that.


Out of curiosity where in the desert do you hike and where would you recommend? I have a particular attraction to being in the American desert but never have hiked it properly.


Southern Utah gives you a huge bang for buck. And you can spread a little further to add fantastic stuff in surrounding states. I'm not American but have flown from Australia several times to hike in Utah and its neighbours.

In 10-14 days, you can do an exceptional loop from Las Vegas taking in:

  Bryce Canyon NP
  Byway 12
  Capitol Reef NP
  Goblin Valley
  Dead Horse Point SP
  Arches NP
  Canyonlands NP
  Goosenecks SP
  Horseshoe Bend
  Antelope Canyon
  Zion NP
  Valley of Fire SP
That's all very accessible (besides The Maze in Canyonlands, which is superb but takes 4x4 and/or solid hiking to get into).

Then when you go back, you can do places requiring a bit more planning like Coyote Gulch (amazing), Buckskin Gulch (also amazing), and secondary spots like Natural Bridges, SR 95, etc. Hundreds of great places in Arizona, New Mexico, Nevada, etc, and all before you get to adding anything more remote or long distance.


The "American desert" can refer to an absolutely huge portion of the continent, and many, many different ecosystems. Its a big enough area of land that it is like saying I like hiking in Europe.

I'm partial to Utah's canyonlands, and a lot of the adjacent pinyon forest (still desert) in Northern New Mexico and Colorado, but that's just where I grew up. The Saguaro forests in southern Arizona are also amazing.

If you've never been to the desert in America, a good plan would be to fly to LA, and drive to the Grand Canyon. You will pass through a number of very different desert ecosystems.


I live in southern Utah, between Zion, Bryce, and the Grand Canyon, right next to Escalante. There's plenty of stuff within a day's drive of here; previously mentioned, plus Canyonlands, Capitol Reef, Arches, and all the state parks, national forests, etc.


And LTO, which is what I actually want, is 2.3 - 2.4 V.


Pretty cool hardware. Count me in if and when it supports interesting software.


There's the rub isn't it? We've been doing AR for over ten years at this point and I can't name a single blockbuster app besides Pokemon Go.


No. The Nobel Peace Prize is awarded by the Norwegian Nobel Committee, while the Literature prize and the other prizes defined by Nobel’s will are awarded by the Swedish Academy.


I see.


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: