HNHacker News
TopNewBestAskShowJobs

cytzol

2,811 karma · joined February 5, 2009

Personal site:

- https://bsago.me

Some of my software projects:

- https://the.exa.website

- https://dns.lookup.dog

- https://specsheet.software

submissionscomments
cytzol··on Richard Stallman: How I do my computing (2015)
The point he's stuck on is that the versions of 'read', 'eval', and 'print' in Python aren't the same as the ones in Lisp. In Python, you read a string, eval that string into a value, then print that value. The intermediate representation is a string -- just a bunch of characters. In Lisp, you read a data structure, eval that data structure into another data structure, then print out its form -- nested lists and atoms that you can inspect and manipulate, rather than characters that you need to parse to do anything useful with.
cytzol··on How to Avoid Being Called a Bozo When Producing XML (2005)
I’ve done it. It’s painful enough that it teaches you “don’t do this!”. For example, you need to escape `{{ item }}` as `{{ "{{" }} item {{ "}}" }}`!
cytzol··on iTerm2 v3.0 Released
Same here -- reverting the font rendering was the first thing I did. Odd decision on the dev's part to make it the default. Really happy about all the other features, though!
cytzol··on Blue. No, Yellow
Here’s my real-world example for why type-level null checking is a good idea.

Let’s say your application tracks users, and each user needs to have at least one address. On top of that, they must flag one address as their default address, which is used when sending them formal communication, but usually they can pick which address they want to use. (Most people have one address which is their default).

The Java code to pick out a user’s default address is simple enough:

    class User {
        // ...
    
        public Address getDefaultAddress() {
            for (Address address : getAddresses()) {
                if (address.isDefault()) {
                    return address;
                }
            }
        
            throw new AssertionError("User has no default address");
        }
    }
We throw an AssertionError here instead of returning null because if a user has no default address, then that’s a bug in the program, and we want to fix it. And because it throws, we can safely assume that any address coming out of getDefaultAddress is not null.

Then one day we receive a change request from a client. Some users move around a lot, and have no permanent address, and they’d like it to be changed from at least one address to at least zero addresses. Basically, make it so users don’t have to have an address anymore.

How does this affect our getDefaultAddress function? It has to handle the case where users have no addresses, because if that’s the case, then they’ll have no default address, either.

The easiest way to do it is just return null instead:

    public Address getDefaultAddress() {
        for (Address address : getAddresses()) {
            if (address.isDefault()) {
                return address;
            }
        }
    
        // no default address
        return null;
    }
With this in place can no longer assume that the Address returned from getDefaultAddress() is an actual Address object. Which means that all the code we’ve written so far -- the code that assumes that the method doesn’t return null -- will break. So we have to find every place in the code where this method is called, and make sure that it does a null check. IDEs can help here, but they can’t help with developers who hadn’t noticed the change and continue using the method in the old way, or places where the method is called with reflection... and do you really want to test every call site to make sure you’re handling it correctly?

Or we can use Optionals:

    public Optional<Address> getDefaultAddress() {
        for (Address address : getAddresses()) {
            if (address.isDefault()) {
                return Optional.of(address);
            }
        }
    
        // I know I could use Java 8 streams here, just go with it :)
        return Optional.empty();
    }
The Optionals aren’t the most important part of this example -- it’s that the method signature changed. Our program will now no longer compile until each and every place in the code that gets a default address has been updated to specifically handle the case where there is none, because the compiler won’t accept an Optional<Address> where it expects an Address. A developer who hadn’t seen the change won’t be able to use the function in the old way by accident, as it won’t compile.

This is precisely what happened to us. Changing the method to return null resulted in lots of breakage from code that we forgot to add null checks to and code written afterwards using the old signature by accident. Changing it to return an Optional meant we were forced to update everything, otherwise it wouldn’t compile. No runtime bugs. No developer slip-ups. That’s why I’m in Team Optional.

cytzol··on Deprecating: java.util.Optional.get()?
And sometimes you want a different type of map...
cytzol··on Deprecating: java.util.Optional.get()?
You're right, actually -- it's not more readable. Java developers already understand nulls, comparisons, and if statements.

However, the second version is a lot more brittle than the first. It's relatively easy to change the code and still get it to compile, whereas you'll have a lot more trouble doing that with the first. For example:

1. If you forget to check 'order' for null, it'll still compile fine, because null is a valid value for type 'Order'. But if you try to feed an Optional<Order> to OrderEngine, it won't compile.

2. If you forget to check 'result' for null, it'll still compile fine, and then throw an NPE when you run 'result.succeeded()'. Again, if you try to call check ProcessResult::succeeded in the first example, it won't compile unless you deal with the empty-result case specifically.

3. Say that later on you want to get your stored values back out of the database... and you find a null in there. Where did it come from? If you forget to check 'result' for null and don't do the 'succeeded()' check, you can put a null in the database. Then your program will work fine until you try to call a method on it, at which point it throws an NPE far, far away from the point where you store it. By using Optional and dealing with the empty case, your code won't compile if you try to store null in the DB.

So unfortunately it will be less readable until Java devs adjust themselves to using this new type, but the benefits do exist.

cytzol··on Deprecating: java.util.Optional.get()?
> the outermost pointer can still be null, so you are still vulnerable to a NullPointerException

This is true, but there is a distinction: if your Optional value is null, for any reason, then it's a programming error and should be fixed. If a non-Optional value is null, there's no telling whether it's "allowed" to be null or not. So I never null-check my Optionals in Java -- I'd rather they fail so I can be alerted to them.

cytzol··on Show HN: Min – web browser with better search and built-in ad blocking
So you can access your list of open tabs from anywhere on the screen? Sounds good.

> Multiple browser windows seems redundant with multiple tabs or the Group Tabs mentioned above.

Surely it's the complete opposite: if you have multiple windows, then why do you need Group Tabs?

cytzol··on Show HN: Min – web browser with better search and built-in ad blocking
Could I make a suggestion, from a "keep all the tabs open forever" person? Try to come up with a personal standard of which tab is where -- or at least where you put certain types of tab -- so you aren't just searching through everything, or toggling back between the last two or three items, but picking the one you want in one exact motion. For example: personal window in the top right with the first tab chat and the second tab e-mail; bug reports go on the left with the one you're currently doing on the far left; searches for programming help usually are centre-to-right with the left tab for google, and all the other tabs for the results... It's not an exact science (you don't need to write a program in your head that determines where to put each window) but I find I can trust my instincts on where I put something most of the time.

(That's how I work and I still hit the wrong window a lot, so take this advice with a heaping bowl of salt)

cytzol··on Vim 8.0 is coming
I find it strange that you find it strange, because I agree: leave the window-managing to the window managers, and the text-editing to the text editors! I posted a very similar reply to a comment about the Min browser; too many applications try to re-invent basic concepts such as windows or tabs. All a text editor should do is give you windows to work with, then leave it up to you to position them.
cytzol··on Vim 8.0 is coming
Like a lot of things in technology, everything forms an island where you start to really appreciate the things you have and ignore the things you don't. If you use any other editor, I'm sure you'd miss being able to zip around editing files the same way I miss session persistence!

But yeah, that's pretty much my objection -- it's not a big one, and there's room in the world for more than one type of software. I'm aware of tmux, but it just shifts the problem from vim to tmux: once you need to upgrade tmux, or your OS, or your computer, everything you've set up gets lost, and I really don't want that to happen.

I'm also aware of things like teamocil, and I even used itermocil for a while. But it turns out that the kind of environment edits I like to make are ones that I just do, rather than ones I can specify in a config file then restart to set everything up again. For example, when you say:

> If you are just exploring the code base or making small edits here and there you don't really need persistent tmux session for that.

Coincidentally I do have a relevant example for that. Last week, when I was exploring the files that make up the zoneinfo database, I put the files that I needed to keep referring to (of which there were like 5) to the side, knowing full well that they wouldn't go away. Then they just stayed there for a while as I got distracted with other stuff. This week, when I had to return to it, they're still there; and all the files from the other projects I'm working on are all in their positions, too, ready for when I switch back next week, surviving through a system restart and an editor upgrade.

cytzol··on Vim 8.0 is coming
Yeah, I do still use vim on remote sessions where I know I'm just going to be making a small change and then be done with it -- losing your entire environment or history is a lot less worrying in that case, and it's way easier than mounting the server locally or something.

However, as someone once said: "The universe tends toward maximum irony. Don't push it." If you don't close vim and keep it open for weeks, then all your environment changes are going to keep on building up, only for you to lose everything the next time you need to restart your system, or upgrade your editor or terminal, or your OS crashes, or there's a power failure, or your computer catches fire.

cytzol··on Show HN: Min – web browser with better search and built-in ad blocking
The key thing is being able to open a tab/window in the background, when everything I know of automatically tries to bring any new window to the front. But I do agree with your point: every application seems to be re-inventing its own window/tab/document management instead of using the ones provided by the OS. I used to use Firefox with Tree Style Tabs, but then I found out that having multiple windows full of tabs was good enough, and I can use the OS to just arrange the windows without needing to arrange the tabs therein.
cytzol··on Vim 8.0 is coming
It doesn't necessarily have to be skeuomorphic, but I like to burn some processor cycles making different things look different, not necessarily brushed-metal attractive. So my todo-list files don't look like my source code files which don't look my terminal windows, which helps me tell what's what.

(And it's beside the point, but brushed metal has been dead for years by now!)

cytzol··on Vim 8.0 is coming
I apologise in advance if this sounds dismissive, but: I've tried to use both Vim and Emacs and Neovim and Spacemacs, and every time my pain point is that they're designed for use on the command line rather than as an environment I can switch in and out of. I know this isn't strictly true as both editors can be run as separate applications that you don't quit for weeks, but their roots have persisted into how they're expected to be used.

Take my first foray into vi, at its most basic level. I'm at a shell prompt, where I can use vi to edit multiple files, saving each one when I'm done with it and occasionally switching to another window to run something else, coming back when I need to edit more. But there's nothing storing my list of open files or buffers and where they are on my screen, my position in each file isn't saved; it's like vi expected me to spawn a new instance every five minutes.

When I tried emacs, which allows much more functionality inside the editor -- connecting to servers, databases, or hosting shells or debuggers -- it just made the problem worse. If I started a shell inside emacs before stopping the emacs process entirely, that shell won't be there when I get back and my files won't either. If I want to have a specific file on the right-hand side of my screen, emacs will forget where I put it. If I open a file in a new window, that file will be gone. If I want to have a file stand out by changing its background colour to a subtly-different hue, that will have changed back by the time I need to re-open my editor.

I don't like this idea; I don't want my editing environment to be some ephemeral process that's created when I start and gets destroyed when I'm finished. And while Vim has sessions and Emacs probably has three forms of saved states, they don't quite work: no saved window positions and sizes, no working with files you haven't given a name. I imagine that it's the same feeling you get when you read that something allows Emacs-like functionality: on a checklist, they might both have tick marks on each row, but when you try to use it, it doesn't work how you expect. I think that Emacs and Vim's command-line history have made its users used to this behaviour, spawning all sorts of tools to make configuring your environment easier instead of just trying to save the changes as they happen. I've seen plugins like CtrlP or projectile that enforce the idea that your environment shouldn't last, you can just set it up again each time. And that means you don't bother personalising your environment and putting things where you want them to be, because it's all going to be irretrievably gone if your computer crashes, so don't get attached. Alright, rant over.

cytzol··on GitHub is down
Ah, I see. In that case, you're right, it's not: if you track issues and docs like like in the same way as you track source files, then functionality-wise they're no different.

The differences that remain are purely in the interface. For example, although they're synced the same way, VCSes tend to display issues differently than source; it's easier to filter out issue changes from the timeline, and harder to accidentally delete other people’s comments. It also makes it possible for people who aren't actual members of your project to raise and comment on the issues, which wouldn't usually be possible (unless your VCS can manage permissions for each file).

One particular use case of yours that Fossil does support is the ability to have a "wiki/" subfolder and have the web interface automatically format and display the pages inside, so you can link to them more easily if you're using the HTTP server for hosting. I think I use this feature more than the built-in wiki because it’s possible to version the docs along with the source, ensuring they never go out of sync.

cytzol··on GitHub is down
Argh, I don’t actually know, and I probably should. I’ll ask on the mailing list and reply with what I find out.
cytzol··on GitHub is down
> why would it require special care?

It doesn't, really, but it's in the same place as the code and everything else (this is what I meant as being "on the same level"). You don't need to clone the code and then clone the tickets, for instance. When you run "fossil timeline" on your local machine, you'll see entries for tickets being closed and wiki pages being updated interspersed among the actual code commits. This is useful to me as they're as much a part of the project as the code itself. Does this answer your question?

cytzol··on GitHub is down
Heh, don't worry, I got the joke. But I also got the joke the last time this was posted, and the time before that, and the time before that...

This just keeps happening. It's not GitHub's fault that they keep getting DDoSed or have a network outage every now and again. But it's not a problem with no solution.

cytzol··on GitHub is down
We do, it's called Fossil! http://fossil-scm.org/

Fossil tracks issues (tickets), documentation, and wiki pages at the same level as it tracks code, so when you clone a Fossil repo, everything gets downloaded to your local computer. You can then respond to tickets and perform repo maintenance offline, syncing everything to the server when you're back up.

Edit: A few weeks ago I got a job a one-hour train ride away. I can commit, close tickets, and write docs on my way in, sync everything to the internet when I get to work, then do the same on my way back - even though I don't have a net connection during my commute. It works great. (Ok, not as good as not having to travel at all, but great nonetheless!)

cytzol··on Google 'mic drop' Gmail joke for April Fools' day backfires
> From what I seen, the buttons didn't change

It replaced the Send And Archive button that lives next to Send. (Adding a new one is still a bad idea, imho, but would have been borderline forgivable)

cytzol··on Google 'mic drop' Gmail joke for April Fools' day backfires
Or maybe the buttons I click shouldn't suddenly change without warning? This isn't a case of a user ignoring an important dialog box then wondering why their computer doesn't work anymore; the button just suddenly started to do something different, which is terrible user interface design.

To put it another way, how am I supposed to get anything done when I'm spending all my time making sure the interface doesn't change beneath my feet?

cytzol··on Google 'mic drop' Gmail joke for April Fools' day backfires
It's important to avoid the thought-terminating cliche "Oh, it was just human error" and look at the problems in the UI that cause the errors in the first place. If the ignition in your car was one day replaced by an ejector seat, and you hit it without thinking because that's what you do every day, I doubt you'd be placing the blame on yourself.
cytzol··on Java for Everything (2014)
I actually find I don't need Apache Commons or Guava now that I'm using Java 1.8. A lot of the functionality has been standardised.
cytzol··on Android N’s freeform window mode
That would be nice, but I'm not holding my breath; the existing code will probably assume one window. We've brought up being told that singletons are bad and should never be used, and then go and build programs like this!
cytzol··on Android N’s freeform window mode
This feels like a step backwards for me, too, and I love overlapping windows and never split my screen. The benefit of having multiple windows is that you can have different working contexts that don't overlap, which makes it easier to find the exact window you're looking for. But look at the screenshots in the article: you still get one web browser window, one calculator, one instance of every app. You can't split (say) the browser into Tabs for Project A and Tabs for Project B, or keep a calculation open for Project B then open a new one without destroying the old one. (Contrived examples, perhaps, but those are the only apps demonstrated in their screenshots so far. Imagine it with text editors.)
cytzol··on Screenshots from developers: 2002 vs. 2015
The advantage (for me, at least, on a Mac) is that it's easier to pick which terminal you want when they're laid out across the screen instead of all being in the same position: "The window I'm testing my code in is in the bottom right", "The window I'm compiling that large thing in the background is off to the left", "The window I'm running my backup script is up at the top".
cytzol··on Mercury Spill
Just curious: what would it need to be for it to do something? Not that I'm planning to...
cytzol··on Differences Between Perl 5 and Perl 6
Oh! I could have sworn it was necessary. My bad.
cytzol··on Differences Between Perl 5 and Perl 6
Any Perl 6 code will have to include a `use v6;` instruction at the very top of the file, so there's no chance of Perl 5 code being confused for it. Is this what you mean?

EDIT: this was completely wrong, see below.

← PreviousPage 7 of 11Next →