Hacker News new | ask | show | jobs
by lights0123 302 days ago
exit(), execve(), and friends do immediately stop execution—I could understand why you'd think a redirect would as well.
4 comments

Exactly. Given that JavaScript runs in the context of a page, redirecting off of the page seems like it should act like a "noreturn" function...but it doesn't. That seems like a very easy mistake to make.
Until they don't. A common issue is not checking if the execve() actually worked and thinking nothing after the execve() will execute, which is an assumption that it not always true.
See, that's what they meant about making assumptions upthread:

https://man7.org/linux/man-pages/man3/atexit.3.html

The redirect is an assignment. In no language has a variable assignment ever stopped execution.

    $ python3
    Python 3.13.7 (main, Aug 20 2025, 22:17:40) [GCC 14.3.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class MagicRedirect:
    ...     def __setattr__(self, name, value):
    ...         if name == "href":
    ...             print(f"Redirecting to {value}")
    ...             exit()
    ... 
    >>> location = MagicRedirect()
    >>> location.href = "https://example.org/"
    Redirecting to https://example.org/
    $
You're overloading a setter here. It's cute, I did it in JS as well, but I don't really think it's a counterexample. It would be odd to consider this the norm (per the thought process of the original blog post).
This is not some weird thing. Here is a run of the mill example where python can have properties settting do anything at all. And it's designed like that.

    import sys
    
    class Foo:
        @property
        def bar(self):
            return 10
            
        @bar.setter
        def bar(self, value):
            print("bye")
            sys.exit()
    
    foo = Foo()
    foo.bar = 10
Or in C# if you disqualify dynamic languages:

    using System;

    class Foo
    {
        public int Bar
        {
            get { return 10; }
            set
            {
                Console.WriteLine("bye.");
                Environment.Exit(0);
            }
        }
    }

    class Program
    {
        static void Main()
        {
            Foo obj = new Foo();
            obj.Bar = 10;
        }
    }

This is not some esoteric thing in a lot of programming languages.
You're also overriding a setter. Maybe I'm going against the grain here, but it's absolutely esoteric. The assignment operator is not supposed to have side-effects, and maybe this is the logician in me, but the implication that we should be aware that weird stuff might be happening when we do `x = 5` is fundamentally bonkers.
You started with "In no language has a variable assignment ever stopped execution", and now you're saying "The assignment operator is not supposed to have side-effects". location.href is a counterexample, and there are many counterexamples throughout various tools and languages and libraries. Deciding how you think things should work does not affect how things do work, and it's important to understand the latter. (I do agree it's bad practice, but it happens and people do not always fully control the environments they must work with.)

And given that location.href does have a side effect, it's not unreasonable for someone to have assumed that that side effect was immediate rather than asynchronous.

That said, if you don't like working with such languages, that's all the more reason to select languages where that doesn't happen, which comes back to the point made in the article.

Assignment is by definition a side effect.

This whole discussion is completely off kilter by all parties because setting the variable doesn't terminate the script--that's the bug; it simply sets the variable (that is, it sets a property in a globally accessible structure). Rather, some time later the new page is loaded from the variable that was set.

Aside from that, your comments are riddled with goalpost moving and other unpleasant fallacies and logic errors.

FWIW I grew up in the days (well, actually I was already an adult who had been programming for a decade) when storing values in the I/O page of PDP-11 memory directly changed the hardware devices that mapped their operation registers to those memory addresses. That was the main reason for the C `volatile` keyword.

> The assignment operator is not supposed to have side-effects,

Memory mapped I/O disagrees with this. Writing a value can trigger all sorts of things.

assignments are side effects, even more so when they are done through a setter on an object / class instance
But window.location.href is already an overloaded setter. It schedules a page navigation.
> The redirect is an assignment. In no language has a variable assignment ever stopped execution.

Many languages support property assignment semantics which are defined in terms of a method invocation. In these languages, the method invoked can stop program execution if the runtime environment allows it to do so.

For example, source which is defined thusly:

  foo.bar = someValue
Is evaluated as the equivalent of:

  foo.setBar (someValue)
Try this in C:

*(int*)0 = 0;

Modern C compilers could require you to complicate this enough to confuse them, because their approach to UB is weird, if they saw an UB they could do anything. But in olden days such an assignment led consistently to SIGSEGV and a program termination.

Unless you were on systems that mapped address 0 to a writable but always zero value so they could do load and store speculation without worry.

IBM did this for a long time

My favourite were older embedded systems where 0 was an address you actually do interact with. So for some portion of the code you WANT null pointer access. I can't remember the details but I do remember jumping to null to reset the system being pretty common.
Probably the system interrupt table. Index 0 might reference the handler for the non-maskable interrupt NMI, often the same as a power-on reset.

I recall that on DOS, Borland Turbo C would detect writes to address 0 and print a message during normal program exit.

RANDOMIZE USR 0
In Wasm you can read/write whatever to address zero of linear memory.

It's still UB as far as clang is concerned so you C code can do whatever. But it won't “crash” on the spot.

You could overload operator=() in C++ with a call to exit(), which fulfills "variable assignment that halts the program".
And for a Rust contrived example, making += terminate execution,

    use std::ops::AddAssign;
    use std::process;
    
    #[derive(Debug, Copy, Clone, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
    }
    
    impl AddAssign for Point {
        fn add_assign(&mut self, other: Self) {
            *self = Self {
                x: self.x + other.x,
                y: self.y + other.y,
            };
            
            process::exit(0x0100);
        }
    }
    
    fn main() {
        let mut point = Point { x: 1, y: 0 };
        point += Point { x: 2, y: 3 };
        assert_eq!(point, Point { x: 3, y: 3 });
    }
I was ignoring these kinds of fancy overload cases, but even in JS you can mess with setters to get some unexpected behavior (code below).
idk if I'd consider overloading the assignment operator to call a function, then using it, actually an assignment in truth.
Well, when you read the source of the caller, it looks exactly like a normal assignment.
That doesn't seem that obvious to me. You could have a setter that just calls exit and terminates the whole program.
Yeah, this is actually a good point, could have a custom setter theoretically that simply looks like assignment, but does some fancy logic.

    const location = {
      set current(where) {
        if (where == "boom") {
            throw new Error("Uh oh"); // Control flow breaks here
        }
      }
    };

    location.current = "boom" // exits control flow, though it looks like assignment, JS is dumb lol
In Blink setHref is automatically bound to C++ code [1]. I think it's fair to say that anything goes.

[1]: https://source.chromium.org/chromium/chromium/src/+/main:thi...