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

Since Finnish (and Swedish) only require a few non-English letters, I actually very much prefer _not_ having to use AltGr and dead keys. My solution for improved ergonomics, especially around typing of symbols, is a slightly modified custom Finnish/Nordic keyboard layout: https://github.com/ruohola/finner


Do you know how Safari content blockers are implemented? They by design cannot do much malicious stuff.


I'm part of the team behind Apilytics. We are building an analytics service that is trivial to setup and that is not tied to any single backend framework. Apilytics offers easy to visualize route-specific usage metrics for your API and allows you to see at a glance which of your endpoints get called the most. It can help you throttle specific endpoints or automatically IP-ban bots that are abusing it. We want to be a privacy-first solution from day one, so you'll have full access to all of you raw analytics data at all times, and our middleware client will be completely open-source.

We are currently looking to get interested people to sign up for our free beta. We are looking to develop the initial version closely with our first users! Feel free to ask any questions here and remember to head to www.apilytics.io!


> functions that routinely just return bool (so helpful)

I don't get it? What's wrong with returning a bool?


This applies to function parameters and return values: you almost never want to use a bool. Instead you want to use an enum with two values. Booleans are hard to read in most cases. Obviously there are trivial cases where this isn't the case (eg bool isDigit(char) is completely fine).

Contrived example:

    bool connectToHost(string hostname, bool useSsl);
First problem: if it fails, why does it fail? Some will be tempted to throw an exception. Better is to return some kind of status.

Second problem: you add another version of SSL, now what? If you'd used an enum, it's just another value. If not, you now need to retrofit it.

Better version:

    absl::Status connect(string hostname, EncryptionType encType);
People will often make mistakes when a function has 3 or more booleans and put the wrong value in the wrong parameter. With strongly typed arguments, this becomes a compiler error.

People will extend booleans to add a third value. In Java, for example:

    Optional<Boolean> foo
But it doesn't end there. As I like to say, for when three values for your boolean just aren't enough:

    @nullable Optional<Boolean> foo
Just start with enums.


> People will often make mistakes when a function has 3 or more ...

of anything. This is why non-compatible numeric subtypes are so valuable. Code like "quantity_sold = price" should not compile. You can do the same thing for other types using the same template but IME that's somewhat less common (but does happen: user_name = address!!).

It would be nice to get a variation on std::pair that works in a similar way to Rust's std::result<value, error>, because std::optional is just a dressed up boolean. I did just swipe the std::pair declaration and do that, but having it official would be nice. Especially for the non-throwing version of the standard libraries.


> People will often make mistakes when a function has 3 or more booleans

A function with three or more positional parameters in a language that isn’t badly broken (that is, one that supports keyword and/or structured parameters, which pretty much all significant languages do) is, IMO, a code smell. Even if more specific typing and IDE pulling up signatures can makes it less likely to make usage errors, readability is impaired.


I’m a big fan of `enum class IsFoo : bool { no, yes };`. I find it to be a great balance between type safety and conciseness. If you want your own unique Boolean-like type, that one line is all you need (unless you want operators, etc.)


There's this pretty abstract idea of boolean blindness, which basically boils down to the idea that a boolean by itself must always be associated with an interpretation and said interpretation is external to the boolean. Afterall a boolean by itself is just a single bit of data, 0 or 1, how to interpret that bit is entirely independent of the bit itself.

This means anytime you operate on a boolean, you must somehow recover its interpretation from somewhere, and the argument is that such recovery is error prone and fragile.

The preferred way, presumably, is then to encode the interpretation directly into the type, so for example you use an enum along with pattern matching, or you write a type that wraps a boolean with some value (like a Maybe/Optional type). In effect anytime you have a boolean, you also carry with it its interpretation side-by-side so you don't need to go figuring out how to recover it.

This article goes into it in more depth:

https://existentialtype.wordpress.com/2011/03/15/boolean-bli...

I personally think it's insightful and useful, but there are also downsides to it as well, for example when you need to operate on multiple booleans, it becomes unergonomic and bloated to deal with pattern matching over multiple enums or having to write out a lot of redundant code instead of operating on boolean operators.

Basically consider these two options:

Option 1: boolean blindness.

    bool isEven(int value);

    ...

    if(isEven(x)) {
      print("Even");
    } else {
      print("Odd");
    }
Option 2: Enum

    enum Parity {
      EVEN,
      ODD
    };

    Parity getParity(int value);

    ...

    switch(getParity(x)) {
      case: Parity::EVEN:
        print("Even");
        break;
      case: Parity::ODD:
        print("Odd");
        break;
    }
You can decide which if the two options above is more appealing to you in terms of reading and writing.


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

Search: