'Abusing' the C switch statement – beauty is in the eye of the beholder - <AUTHOR> https://blog.feabhas.com/2017/02/abusing-c-switch-statement-beauty-eye-beholder/ <comment><USER2> I think this looks a _lot_ better if you use "if (false);" at the top to normalize the "else if" in the rest of the chain.

        switch (x) default: if (false);
            else if (valid_command_message(x))
            case CMD1: case CMD2: case CMD3: case CMD4:
                process_command_msg(x);

            else if (valid_status_message(x))
            case STATUS1: case STATUS2: case STATUS3:
                process_status_msg(x);

            else
                report_error(x);

That said, I think the entire concept of this code having both the enum switch and the valid_* functions is just horrible :/.

To be clear, it isn't that I find the code difficult to grok: if you don't understand how switch works, please stop using C.

The issue is that this particular use case for the switch is a _lazy_ performance optimization, as it should just totally replace the valid_* calls if we do that; it is like the author doesn't want to update the switch cases, but wants the code to keep working? Did they just forget the switch exists, or is it that they can't edit it? I just don't get it, particularly when any modern C compiler supports "give me a warning if I don't consume all the possible switch values in this enum", which is the feature that this code should be using, not if < END_*.

BTW: it isn't clear to me that this would even be a performance optimization; in an ironic twist, many compilers are going to choose to compile that switch statement into the moral equivalent of two if statements with range checks, as default has to be implemented as a range check anyway, and if you work out how many range checks you are doing combined with the code cache benefits of having explicit branches instead of implicit jump tables, this switch statement is going to feel extra repetitive when you look at the machine code.

<comment><USER3> >To be clear, it isn't that I find the code difficult to grok: if you don't understand how switch works, please stop using C.

As an aspiring C programmer, is there anywhere I can read about interesting applications of the switch statement? Pretty much everything I've learned has come with neat little break;s and default at the end of each case.

<comment><USER4> If you're an aspiring C programmer don't worry about these weird quirks. Don't believe that you need to know that to use C. A switch statement with "neat little breaks and default" is more than what you'll need 99% of the time.

<comment><USER5> The remaining 1% is a big comment reading "/* FALL THROUGH */" instead of a break. Once you know what break does, you should know what happens when you leave it out (and why you might want to).

The remaining 0% is stuff like Duff's Device.

</comment></comment></comment></comment><comment><USER6> If this sort of thing tickles your fancy, you might also want to read about Duff's Device.

[https://en.m.wikipedia.org/wiki/Duff's_device](https://en.m.wikipedia.org/wiki/Duff's_device)

<comment><USER7> I use duff's all the time in micro-embedded; best way to have 'coroutines' without all the necessary stack switching interface. It has it's limitations of course, but it's a terrific tool in certain circumstances.

<comment><USER8> >> I use duff's all the time in micro-embedded; best way to have 'coroutines' without all the necessary stack switching interface.

Can you provide an example? We use state machines all the time, but I have not seen a good example of mixing other flow control statement into a switch/case outside of Duff's Device.

<comment><USER7> I posted a gist [0] sorry it's not really made for public scrutiny, it's an old pet project clock, a video of most of that code is still there: [https://plus.google.com/+MichelPollet/posts/ARDMrY4jSxp](https://plus.google.com/+MichelPollet/posts/ARDMrY4jSxp)

That code does timer, radio clock decoding, scrolling, blinking and all that using multiple 'protothreads'. As you can see the main loop sleep() and wait for a timer interrupt (or anything) to fire to wake up, so it's not even running most of the time; only when the 'tick' timer fires.

[0] [https://gist.github.com/buserror/9407adb6d52153e16caad5e8a08...](https://gist.github.com/buserror/9407adb6d52153e16caad5e8a0844023)

<comment><USER7> The trick is on the PT_ macros really, they hide the switch, case and gotos. I'll post the header later, but you probably can find it by googling for protothreads

<comment><USER9> Whoa, PT is fantastic.

A full explanation of how it works is here: [http://dunkels.com/adam/pt/expansion.html](http://dunkels.com/adam/pt/expansion.html)

Its actually a really simple and beautiful. I worry that we give up a lot of this sort of flow expressiveness in more modern languages like Rust.

</comment></comment></comment></comment></comment></comment><comment><USER10> Neat `abuse'.

Personally I don't like the what I consider an anti-pattern he used in his refactored functions. I'm talking about doing this:

        if (condition) return true;
        return false;

instead of simply

        return condition;

<comment><USER11> Yeah, I hate that with a burning passion, too.

The only justification I've seen/heard is that it makes it more "debuggable", you can single-step through and see that the expected path is taken, i.e. that the condition is properly evaluated.

Still, I hate it and would much rather check that some other way (by inspecting the return value before the function exits, for instance).

<comment><USER6> If you're going for debuggable, though, you still don't want the if and multiple returns. You'd be better off with something like:

        bool result = (condition);
        return result;

<comment><USER12> This is good, but you do still want the multiple returns as well, because then you can breakpoint one case or the other without any performance degradation when the breakpoint is on the rarer case.

(Also, at least for C/C++, you generally want condition and each case on separate lines, so that you can actually put breakpoints on each thing separately - tool support for multiple independent breakpoints on a single line is still an utter shambles, and you're best off just assuming nothing supports it.)

Unconditional breakpoints that aren't being hit are a lot cheaper (if they even cost anything at all - which usually they don't) than conditional breakpoints that are always being hit...

<comment><USER13> Their will be no difference in this case - the compiler will optimize the boolean foo = {complicated expression}; if (foo){ return true; } else { return false; } into return {complicated expression}, and the debugger will be forced to add a conditional breakpoint.

<comment><USER12> I've never used a debugger that's that clever (and I'm not sure debug info gives it enough to work with to deduce this anyway, not with DWARF at least) - the ones I've used just put an unconditional breakpoint on the instruction the compiler says that corresponds to, and then show it as attached to whichever line it chooses. (DWARF decrees that each instruction is from one source line, but one line may map to many instructions - so there's no perfect way of doing this backwards.)

This is why it's usual to debug the unoptimized build... and why this situation is hypothetical ;)

There's nothing wrong with running an optimized build inside a debugger; in fact, I recommend it, since when it crashes you've then got at least some chance of figuring out what's going on. But for the sort of work where you're putting breakpoints on one clause rather than another, or stepping through code line by line trying to figure out what's happening, it's not very good.

</comment></comment></comment></comment></comment></comment><comment><USER14> My favorite abuse of switch statements in C is to use them for co-routines in C...

[http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html](http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html)

[http://blog.robertelder.org/switch-statements-statement- expr...](http://blog.robertelder.org/switch-statements-statement-expressions/)

<comment><USER15> To add onto this: \- [http://dunkels.com/adam/pt/](http://dunkels.com/adam/pt/)

Even though it is an abuse, these sorts of libraries are fascinating to me: making use of language features in unexpected (most likely unintended) ways.

<comment><USER14> Agreed! (I had forgotten about protothreads, thanks)

</comment></comment></comment><comment><USER16> While we're discussing abuse of switch, here's my personal best effort at misusing this feature, from over thirty years ago.

      /*
       * A program to print The Twelve Days of Christmas
       * using the C fall through case statement.
       *
       * Jim Williams, jim@maryland, 2 May 1986 (but first written ca. 1981)
       */

      /*
       * If you have an ANSI compatible terminal then
       * #define ANSITTY.  It makes the five Golden rings
       * especially tacky.
       */

      #include <stdio.h>

      char *day_name[] = {
          "",
          "first",
          "second",
          "third",
          "fourth",
          "fifth",
          "sixth",
          "seventh",
          "eighth",
          "ninth",
          "tenth",
          "eleventh",
          "twelfth"
      };

      int
      main()
      {
          int day;

          printf("The Twelve Days of Christmas.\n\n");

          for (day = 1; day <= 12; day++) {
              printf("On the %s day of Christmas, my true love gave to me\n",
                   day_name[day]);

              switch (day) {
              case 12:
                  printf("\tTwelve drummers drumming,\n");
              case 11:
                  printf("\tEleven lords a leaping,\n");
              case 10:
                  printf("\tTen ladies dancing,\n");
              case 9:
                  printf("\tNine pipers piping,\n");
              case 8:
                  printf("\tEight maids a milking,\n");
              case 7:
                  printf("\tSeven swans a swimming,\n");
              case 6:
                  printf("\tSix geese a laying,\n");
              case 5:
      #ifdef ANSITTY
                  printf("\tFive ^[[1;5;7mGolden^[[0m rings,\n");
      #else
                  printf("\tFive Golden rings,\n");
      #endif
              case 4:
                  printf("\tFour calling birds,\n");
              case 3:
                  printf("\tThree French hens,\n");
              case 2:
                  printf("\tTwo turtle doves, and\n");
              case 1:
                  printf("\tA partridge in a pear tree.\n\n");
              }
          }
          return 0;
      }

<comment><USER17> That is abusive. You started counting from one not zero.

<comment><USER16> Yeah, well, I was young and inexperienced... my first programming languages were BASIC and FORTRAN...

</comment></comment></comment><comment><USER18> Abuse of the switch statement? The firm bought a company and we found in their source code that they had created a 50,000 case-statement monster.

We asked that they refactor it, and they agreed because the sheer size of it was giving the compiler problems. So they divided it into two separate 25,000 case-statement monsters.

<comment><USER19> That moment when your jump causes a cache miss.

</comment></comment><comment><USER20> This is ridiculous. Sure, I'll agree, it's a neat trick, but what mindset do you need to be in to come up with such a convoluted solution to such a problem, and the wrong problem at that?

What problem does hack this solve? Single point of edit for a new feature? Well, odds are you've added/edited code elsewhere to implement the feature. Saving one edit is pointless. Just do it properly.

What problem is this code trying to solve? Message dispatch. And it does it. Twice. Once to differentiate whether something is a command or a status message, and then once again to actually execute the thing. Silly. Just build a table and be done with it. If you're concerned about performance after you've benchmarked it, write some code to generate a perfect hash and generate your table.

        static const struct message_handler {
            int id;
            void (*process)(int x);
        } tab[] = {
            { .id = CMD1, .process = process_cmd1, },
            { .id = CMD2, .process = process_cmd2, },
            { .id = CMD3, .process = process_cmd3, },
            // ...
            { .id = STATUS1, .process = process_status1, },
            { .id = STATUS2, .process = process_status2, },
            { .id = STATUS3, .process = process_status3, },
        };

        const struct message_handler* find_message_handler(int x);

        void process_message(int x) {
            const struct message_handler *handler;
            handler = find_message_handler(x);
            if (NULL != handler) {
                handler->process(x);
            }
            else {
                report_error(x);
            }
        }

Now tell me which one your code reviewers and juniors are going to prefer.

<comment><USER21> > What problem is this code trying to solve?

I think you missed the point of this hack - the problem he's trying to solve is described in the article:

> The common issue associated with switch statement is typically maintenance; > especially where the set of 'valid' values needs extending.

He wants the efficiency of the switch statement for all the cases he knows about and a fallback to the less efficient if clauses if that fails due to new cases being added. It's a pretty silly example but let's face it - it's more for fun than elegance.

<comment><USER20> I see your point, but I'd argue that even then it's still the wrong the problem.

1\. If you don't enjoy maintaining your switch statement, it's probably huge anyway and you need to refactor.

2\. If you don't enjoy maintaining this switch statement, you probably also don't enjoy maintaining the switch statement inside next function that gets called that gives you your full set of valid values.

3\. The number of types of messages used is probably much fewer than unique messages, so you are optimising on a small N, which will give minimal returns.

4\. You never need to look at this code again and it will just sit there adding overhead. Other switch statements will be maintained because they're the first place you'll notice missing entries.

Fun, sure. Like setting a fistful of matches on fire. It takes a bit of effort to set up, and it looks interesting. I'll agree to that.

</comment></comment></comment><comment><USER22> Where available, my preferred solution is to compile with gcc -Wall -Werror (or equivalent); this will enable -Wswitch, causing a compile error when you fail to handle an 'enum' case. Needing to fix a few obvious compile errors after a change isn't much of a burden; un-maintainable code is code that _silently_ breaks on changes. (The same attitude leads to lot of static_assert().)

(You may also be interested in -Wswitch-enum.)

<comment><USER23> No do not do -Wall and -Werror as Wall is arbitrary between compilers and versions.

<comment><USER22> You're absolutely right that -Werror should not be the default in release tarballs, and I should have included that.

</comment></comment></comment><comment><USER24> > If the implementation uses a form of jump-table then this [switch statement] > has the benefit of giving you an O(1) performance based on the messages, > whereas with the if-else-if chain, the commands will be checked and > processed before status and errors.

The reason for using a switch statement in the first place was so that you'd have constant performance. The argument against the simple implementation was:

> Let's assume in v2.0 of the system we want to extend the message set to > include two new commands and one new status message ... the if-else-if > version will handle the change without modification, whereas the existing > switch statement treats the new commands still as errors.

Treating the new commands as errors is a feature of the switch statement style, not a problem. They need to be added to the jump table, not implemented with reduced performance.

<comment><USER25> Also using big O notation here makes no sense surely? The claim that the switch version is (in contrast) O(1) is not even wrong.

<comment><USER26> Yeah I'm not quite sure I understand this statement either. Does he mean that in the case of a command the first `if` passes and the rest are ignored, but in the case of status and error you need to perform the previous `if`s as well? So then the case for status is what, O(2)? That makes no sense.

If you're going to write something this obscure for the sake of "performance", you want to be damn sure it's worth it -- that performance is even an issue, and that this is a large enough improvement to justify not doing the simple thing.

Honestly it feels like the author wants to do it this way because it's clever, and the "performance" reason is just rationalising it.

</comment></comment></comment><comment><USER27> No need to abuse the C switch statement.

#define while if // make code faster

#define struct union // use less memory

<comment><USER28> Just define all the keywords to be `exit(0);` #performance :)

</comment></comment><comment><USER29> Of all the things I learned in kindergarten this was my favourite :)

In all seriousness, this is.. interesting! I had no idea you could have a case inside default like that.

<comment><USER12> But there is no "inside": case and default are like (slightly restricted) goto labels. They mark a place in the code, nothing more, and, as with goto labels, they can be inside nested scopes. That's why you need the "break" to explicitly leave the switch - because when execution reaches a label, it just continues. The label is a marker, nothing more.

(In terms of restrictions: case/default have to be inside the switch statement somewhere, and not inside some additional switch statement nested within it. But aside from that, as demonstrated by the article, you have a good deal of freedom about where they go.)

<comment><USER29> This was a really helpful explanation, thankyou :)

</comment></comment></comment><comment><USER30> Of course if you were programming in a language with proper macros you could just automatically generate the switch statement from the enums and have the best of all possible worlds.

</comment><comment><USER31> For me, the beauty is when it is apparent on the first sight what the code does. This is just the opposite of beauty (in my eyes :-)).

<comment><USER32> There is more to code than legibility. In general, the priorities are correctness, legibility, legibility, a few hundred more times legibility, then stuff like performance, memory usage, binary size, predictability, etc.

But this is C. C is used on a wide diversity of contexts, and on some of then the order above changes.

<comment><USER33> ... except when performance, memory usage, binary size, predictability are part of the correctness requirement (which is most of the time in the areas C is used).

</comment></comment></comment><comment><USER34> While dealing with unhandled enumeration constants you can get help from most compilers; for gcc:

      #include <stdio.h>

      typedef enum tagCmd { cmd1, cmd2, cmd3 } Cmd;

      void doCmd(Cmd cmd )
      {
            switch(cmd)
            {
                    case cmd1:
                            printf("Cmd1\n");
                            break;
                    case cmd2:
                            printf("Cmd2\n");
                            break;
                    //case cmd3:
                    //      printf("Cmd3\n");
                    //      break;
            }
      }

      int main()
      {
            doCmd(cmd1);
            return 0;
      }

Now

      gcc -Wall  t.c
      t.c: In function 'doCmd':
      t.c:7:2: warning: enumeration value 'cmd3' not handled in
      switch [-Wswitch]
        switch(cmd)
        ^

Now

      gcc -Wall -Werror  t.c
      t.c: In function 'doCmd':
      t.c:7:2: error: enumeration value 'cmd3' not handled in
      switch [-Werror=switch]
        switch(cmd)
        ^

Or rather the following: (if you don't want to deal with a lot of other errors/warnings)

      gcc -Wswitch -Werror  t.c
      t.c: In function 'doCmd':
      t.c:7:2: error: enumeration value 'cmd3' not handled in
      switch [-Werror=switch]
        switch(cmd)
        ^

If you put in a default statement then the compiler will not be able to help you here.

</comment><comment><USER35> This is just terrible. The fact that the compiler complains if an enum is added without updating the switch statement is a feature. The enum and switch version is clear and explicit. To defeat it, in the name of... what, code obfuscation? beggars belief.

</comment><comment><USER5> I guess the reminder that C's switch syntax is bizarre and flexible is amusing, but this is still really wrong-headed. Friends don't let friends write code like this!

We're told we have "process_command_msg" and "process_status_msg" functions. Each of those functions is _already_ doing a switch or if/else to determine the exact message type. If you care about the cost of those lookups, the correct thing to do is have a single switch statement that handles all the messages at once.

If you don't care enough about the cost of lookups to split up those functions, you should stick with the obvious if/else test.

Another thing you could do to improve the design is to have a "get_message_type" function returning a "COMMAND_TYPE" or "STATUS_TYPE" enum, then switch on that. That can be made efficient if you really care about execution cost (for example, check a single bit, and inline it so the switch can be optimized).

Abusing the switch statement not only gives you unreadable and bug-prone code, it simply isn't any better than a sensible approach.

</comment><comment><USER36> Macro lists are a rather elegant solution IMO. You cannot add cases to the enum without also adding cases to the switch.

      #define CMD_LIST CMD(1) CMD(2) CMD(3) CMD(4)
      #define STATUS_LIST STATUS(1) STATUS(2) STATUS(3)

      enum {
        #define CMD(x) CMD ## x = x - 1,
        CMD_LIST
        #undef CMD
        END_CMD
      };

      enum {
        #define STATUS(x) STATUS ## x = x + 9,
        STATUS_LIST
        #undef STATUS
        END_STATUS
      };

      void process_message(int x)
      {
        switch (x) {
          #define CMD(x) case CMD ## x:
          CMD_LIST
          #undef CMD
            process_command_msg(x);
            break;
          #define STATUS(x) case STATUS ## x:
          STATUS_LIST
          #undef STATUS
            process_status_msg(x);
            break;
          default:
            report_error(x);
            break;
        }
      }

It's unfortunate that it isn't possible to write a macro macro that expands to that gross def/undef boilerplate we use in the switch.

<comment><USER37> You can use an x-macro:

      // cmds.def
      X(1)
      X(2)
      X(3)
      X(4)
      #undef X

      // elsewhere.h
      enum {
      #define X(x) CMD##x = x - 1,
      #include "cmds.def"
        END_CMD
      };

Or a higher-order macro:

      #define CMD_LIST(X) X(1) X(2) X(3) X(4)

      enum {
      #define CMD(x) CMD##x = x - 1,
        CMD_LIST(CMD)
      #undef CMD
        END_CMD
      };

</comment></comment><comment><USER38> People may disagree but if the function valid_command_message already bounds checks x, isn't the case statement redundant? Do you really want the same bounds check in two different places? Maybe in embedded programming you do for safety but it seems like a simple if test is sufficient.

<comment><USER39> The switch jumps directly to the case labels, skipping the valid_command_message call. At least that's the concept, but you better know what your compiler makes out of it.

So this might be useful if you want the jump table performance now on the known values, but you suspect that in the future some maintainer might add more values to the enums and forget about the switch, because maybe the enums are hidden in some header file far away.

</comment></comment><comment><USER40> I'm the author of libb64[1], which (ab)uses the switch statement in a similar way to implement a base64 encoder and decoder. This was inspired in turn by "Coroutines in C"[2], written by Simon Tatham.

[1] [http://libb64.sourceforge.net](http://libb64.sourceforge.net)

[2] [http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html](http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html)

</comment><comment><USER41> It's impressive that clang generates the same assembly for both versions: [https://godbolt.org/g/yLh1EF](https://godbolt.org/g/yLh1EF)

Note that the assembly for process_message2 calls each function only once even though some appear twice in the body.

</comment><comment><USER42> 1) All four versions are O(1)

2) Textually interleaving two implementations is bad no matter what language you're in

3) You could achieve the same effect with gotos without giving anyone a migraine... but it still wouldn't be worth it

</comment><comment><USER19> So the main point here is we save some time with a direct jump at least for a few values of x? It's cool I guess but the extra confusion might not be worth it.

<comment><USER43> The author is coming from the embedded world, where saving time in an important loop can determine whether or not your code can operate in the required time windows. Keep in mind that there are a lot of micros out there that are being used for new projects that have memory amounts in the hundreds or even tens of bytes. When you start getting into those areas, sometimes you have to cheat to get things working.

<comment><USER19> Sure, in that case, then I agree with the saurik. The solution is you just put in more labels in your switch statement. And, if you aren't so keen on that sort of discipline, use a macro ALL_CMDS so you don't have to change nine places in the code.

Go "O(1)" on all the CMDs or don't, for the sake of ease of comprehension. In the hypothetical, or may be practical world[0] where size+computation constraints require you must goto some of them and if-else the rest of them, I suppose the "1/2goto,1/2if-else" optimization would be one of the latter considerations for optimization over a host of other things you can consider.

[0] I admit I don't hack in that world, but I do computational physics, which is more about vectorizing things, not optimization of branching typically.

</comment></comment></comment><comment><USER44> Meh, this is pointless, the compiler chooses if ranges or jump table regardless of which form you use here. But it probably makes you feel better :)

</comment><comment> loup-vaillant "Fixing" the switch statement.

      #define case    break; case
      #define default break; default

There, no more fall through.

</comment><comment><USER45> Partly related:

Simulating the C switch statement in Python:

[https://jugad2.blogspot.in/2016/12/simulating-c-switch- state...](https://jugad2.blogspot.in/2016/12/simulating-c-switch-statement-in- python.html)

Not a proper simulation of C's switch, has limitations mentioned in the post, just something I whipped up for fun.

</comment><comment><USER46> Interesting ideas, but this bothers me: "Then refactored to:"

Refactored implies performance improvement to me, and inlining is _almost always_ faster than the more modular representation that the author ended up with after "refactoring" (putting the comparisons in functions).

<comment><USER47> Readability improvements and complexity reductions are often more important than performance improvements and very good reasons to refactor.

</comment></comment><comment><USER48> I think you can probably get by with an array of function pointers, and bittwiddling to get values.

For example, if i is the ENUM code that was passed, then 1 ^ ((unsigned int)i >> (sizeof(int) * sizeof(char) - 1)) will be 0 if negative and 1 if positive or zero.

</comment><comment><USER49> I didn't learn this in kindergarten, but I did learn about Duff's Device in the 7th grade (as it turns out, the Jargon File makes for pretty good reading during boring classes).

Never had cause to implement it, though, and never saw this particular hack.

</comment><comment><USER50> Modal behavior should implemented through subclassing, not switches or if tests. This has the property of consolidating all code for a class in the same code file and not scattered among larger pieces of code. Much easier to maintain and extend.

<comment><USER51> What classes? This is C not C++ or C#.

I don't dispute that one can use C for class based coding but it isn't common.

</comment></comment><comment><USER52> Many compilers now support a range selection extension on case labels, so you can just do:

        case CMD .. CMD_END: /* whatever */ break;

</comment><comment><USER53> Did I miss an explanation somewhere? Why are the `process_` functions referenced _again_ in the default case? That has a code smell.

<comment><USER54> The first version references them to allow for a single point of refactoring to increase the number of command messages or status messages (the valid_xxxx_message() function call). He recognizes this as a not ideal and then refactors the code to have both the benefit of the jump table created by the switch statement and the benefit of the if statement (the single point of refactoring).

<comment><USER53> I see now. If we add to the `enum`s and forget to update our `switch`, we still get the chance to process new commands, albeit with a minor performance hit.

Personal opinion: Unit tests should be used to let you know when you forgot to add in new `case`s.

<comment><USER33> So, what lets you know when you forgot to update your unit tests for the new cases?

Checking for switch/case completeness is the job of the compiler and -Wall -Werror.

<comment><USER53> The fact that you got output from `report_error()`

</comment></comment></comment></comment></comment><comment><USER55> It always amaze me how many people is 'discovering' the C switch statement for the first time.

</comment><comment><USER56> well, I dont see the beauty :)

</comment><comment><USER57> There's just no reason to have a web site that goes down when HN viewers go to it.

I run wiki.luajit.org on a VM, using Gollum. We got hit by HN a while back. CPU went from 1% to 2%.

People saying "CPU is commodity" tend to write software which uses all available CPU... for little purpose.

Heck, I worked at a company which did just that. "CPU / memory / disk is commodity, use it." And they did! Soon enough, all CPU / memory / disk was in use, and they had to go back and re-architect their software so that it wasn't crap.

It would have been cheaper to do it right in the first place. But religious beliefs about engineering over-rode actual engineering.

</comment><comment><USER58> This is a whole stack of horrible code under the banner of "might be more efficient" with no actual examination of what the code actually gets compiled into, much less any profiling.

</comment><comment><USER59> Cool trick, but difficult to grasp on first glace. I'd personally rather see pages of 'if' statements if it makes it easier to reason about.

</comment><comment><USER60> He's got a good point: Why is C still the staple it is? But I believe that Rust is going to take it's place. Not sure whether it's a good thing, but this trick isn't possible in rust ;)

Rust would give an error when an enum isn't exhausted in a match clause. So the issue being described doesn't exist :D

<comment><USER61> > Rust would give an error when an enum isn't exhausted in a match clause. So > the issue being described doesn't exist :D

I was going to say something like that, but the equivalent code would have a "_" case in the match statement. I don't know rust yet, but would a rust programmer typically make a point to not use a "_" (default) statement so that you can catch these at compile time and expect you'll never have anything else?

<comment><USER62> It's not just typical, it's _required_. If you add a default match when you've already specified all the possible cases, the compiler gives you an error. Here's an example ([https://is.gd/KjSc8B](https://is.gd/KjSc8B)):

        enum Foo {
            Bar(i32),
            Baz(i32),
        }

        fn matchfoo(f: Foo) -> i32 {
            match f {
                Foo::Bar(x) => x,
                Foo::Baz(x) => x,
                _ => 42
            }
        }

gives "unreachable pattern", a hard error, for the "_" case.</comment></comment></comment>


Why You Aren't As Successful As You Want To Be - <AUTHOR> http://www.chrisbrogan.com/notsuccessful/

<comment><USER2> While I agree with the whole article, I take issue with the phrasing of the title - You _are_ exactly as successful as you want to be if by 'you', you mean your procrastinating, excuse-seeking, risk-averse subconscious. You know, the 'real' you, as opposed to the marionette who answers questions like this and naively thinks it's control ;)

It's a simple change of perspective that, if you can hold on to it, will give the marionette some real power to notice and correct self-harming and/or restricting behaviour.</comment>


A Year of Running a SaaS "Side Business" at Priceonomics - <AUTHOR> https://priceonomics.com/a-year-of-running-a-saas-side-business-at/ <comment><USER2> Can you let us know why you build it in the first place since there are over a dozen apps that do this already? I'm sure yours has features that stand out from others after you start building it, but what is the motivation to build it at first? What did you need that other apps don't provide?</comment>


Great Circle Mapper - shortest distance between 2 points on Earth - <AUTHOR> http://www.gcmap.com/

<comment><AUTHOR> this one is cool <http://www.gcmap.com/mapui?P=auk-CPT></comment>


How to get high right now behind your screen? - <AUTHOR> http://www.highlinux.com/wanna-get-high/?how

<comment><USER2> wts?</comment>


What is the best ETL tool and why? - <AUTHOR> <comment><USER2> I don't know if there is a best. I think most ETL tools look similar how they visualize dataflows, and in what they do.

I think SAP BW is pretty good if you are an enterprise. Especially if you have a large SAP Landscape. Then extracting data is simple and fast.

Pro I like their concept of infoobjects to organize the metadata. I like the way you can schedule jobs and monitor these. I like the programming features to customize SAP BW.

Cons I do not like the GUI, but newer versions look more modern. Licenses. Expensive.

</comment><comment><USER3> 3 of the best ETL tools on the market today:

Informatica [https://www.informatica.com/products/data- integration/powerc...](https://www.informatica.com/products/data- integration/powercenter.html)

Diyotta [https://www.diyotta.com/](https://www.diyotta.com/)

Talend [https://www.talend.com/products/talend-open- studio/](https://www.talend.com/products/talend-open-studio/)</comment>


How to Find Your Earliest Users - <AUTHOR> https://www.indiehackers.com/round-table/how-did-you-find-your-earliest-users <comment><USER2> For us (Dependabot) the best advice I ever got was that your initial customers should come from sales, not marketing, even for a really low-price SaaS product. I was literally giving Dependabot away for the first 6 months of its existence, but I was still doing concierge sales on it.

When you sell to customers directly you get to hear their reactions and get a much better sense of what's valuable to them. You also make yourself more approachable if/when they've got feedback down the line. Finally, you get a predictable return to your effort (even if it's low!), which prevents the kind of boom and bust that can burn you out in the early days.

I'd really, really highly recommend anyone else looking to start a B2B business take the same approach, even if your product is way too cheap for sales to be scalable.

<comment><USER3> This hits home. Literraly signed up the first paying customer for my monitoring SaaS [0] two days ago. It was done through discussing issues over mail, a tiny bit of "hand holding" and treating the customer as a launching partner (which they totally are). That first Stripe notification is pretty awesome [0] [https://checklyhq.com](https://checklyhq.com)

<comment><USER4> Just checked out your site. Two things I ran into, the first was that the site seemingly wouldn't load. So I quickly typed in [https://www.checklyhq.com](https://www.checklyhq.com) and it doesn't resolve. Then I went back to the original url and gave it a bit of time, took maybe eight seconds to load the content, and it's doing that every time (HN flood?). It seems like something is fully loading, blocking the page load, before it finally displays the whole page.

Anyway, I'd definitely suggest redirecting the www to the naked domain.

<comment><USER3> Thanks for the tips. Crazy how things like this can slip. The site is static and on AWS Cloudfront, but it's a quick port from the actual Vue.js app which makes it rather big. Will make it server rendered (and faster) in the future. For now just reshuffled some v-cloak tags which should result in a quicker experience.

</comment></comment></comment></comment><comment><USER5> For a tech product, look no further than where you are right now. HN has been one of the best sources of users for EnvKey[1], a developer-focused configuration and secrets manager. While HN has a reputation for toughness, it's also full of early adopters who will give you great feedback and be understanding as you figure things out.

And don't be afraid to play small ball. Of course it's amazing to get on the front page of HN, PH, big subreddits, etc., but it's also hit-or-miss and subject to the whims of the hivemind. Posting comments in relevant threads is slower, but it can drive a surprising amount of traffic over time, and the conversion rates will often be _much_ higher than a 'featured' placement.

Of course, you need to take care that you're adding something to the discussion and not just advertising. Basically, your comment should be able to stand on its own as something valuable _without_ any mention of your product, but make people curious about what you're doing, so that by the time they get to your link, they actually want to click it and learn more.

Another tip: if you have a product that has sdks for various languages, integrations with other platforms, etc., treat each one as a mini-launch to that community. It's often _much_ easier to get attention with "here's a cool new thing for Elixir" vs. "here's something for everyone".

1 - [https://www.envkey.com](https://www.envkey.com)

<comment><USER6> This has definitely been the case for me over at breachinsider.com too – the ShowHN brought our first handful of customers, which have been a real delight to work with and completely fit the description outlined above... they understand the position we are in, and are happy to report issues or bugs they find (and are happy when we fix them in hours rather than weeks).

Generally speaking (and not in anyway a comment directed at the lovely people behind EnvKey), it can be a double edged sword, as if you are seen to _only_ plug your business, even if you do add to the conversation, it can come across as a little disingenuous or pushy. So if you do take this route, don't forget to be human and post normally sometimes.

<comment><USER5> > So if you do take this route, don't forget to be human and post normally > sometimes.

Great point. As an inveterate HN addict, this isn't an issue for me, but it's important to strike a balance.

It's like asking friends for favors. It's totally fine, but if it's the only reason you ever get in touch, it will start to get old.

</comment></comment></comment><comment><USER7> When I started browserless.io, I was having a heck of a time getting Chrome running properly in Docker. After about 1 month of hit-n-miss `docker build`'s (which was taking ~15 minutes each time due to the amount of deps and lack of layer caching therein), I decided to sort popular open-source libs by comments and reactions. To my surprise I wasn't the only one experiencing this issue!

This actually turned out to help in two ways: I knew _exactly_ what to build, and where to find first users. After that I point I really haven't had to market or even cold-call anyone since (thanks to SEO and GitHub) most folks find the solution when there in the midst of the problem.

If you're looking to build something, and are tech-savy, I think it's an interesting thing to go to popular OS projects and do some research. It'll open your eyes as to what others are needing and (sometimes willing) to pay for.

<comment><USER8> I agree, you can find a lot of peoples pain points from just going to forums.

Looking back now, it amazes me at how often you see people crying out for a solution that they want to pay someone for. Mainly CMS plugins, but there's still a lot of opportunity out there.

Also, nice product!

</comment></comment><comment><USER9> Common sense theme here: focus on a small group of people and delight them. If they're having the same problem, chances are others are as well. Be authentic, work smart, and deliver value based on what people are telling you.

<comment><USER10> I liked this for contrast:

 _Additionally, when we started the company I didn 't have much money, but I saw that the most commonly searched term for SoundCloud producers was "How do I get more Reposts on SoundCloud?" A repost on SoundCloud is like a retweet on Twitter, so artists want as many of them as possible so their music will get heard.

I thought if I named the company Repost and dominated the SEO on that specific search we could get some free inbound traffic. My assumption worked. I believe if you search "SoundCloud repost" in Google we're one of the top hits, and something like 25% of our inbound applicants come organically._

<comment><USER11> I found this one very interesting too. I wanted to ask the founder how he knew "the most commonly searched term for SoundCloud producers was..." Is this somethig someone just threw out as a bit of anecdotal evidence? A running joke in the community or common knowledge among fellow producers? Or was there a specific analysis of say Google trends he did to come up with this nugget of insight? I think if you can identify a common search terms for a niche group then you can find common problems to solve... But how did he do that or know that?

<comment><USER12> As part of its marketing products Google used to have a keyword analysis tool that enabled the look up of search statistics for keywords. It also recommend keywords based on a target URL. They've changed their tools since I used it last, but I assume something similar still exists.

The approach of discovering a keyword niche and targeting it is harder now that more people know about the technique.

</comment></comment></comment></comment><comment><USER13> I'm going through this right now with my real estate related site OpenHouseTour[1]. It's definitely different (and eye opening) when you're dealing with clients that aren't as savvy with computers and you're having to explain how to do things like copy and paste. I try to take the XKCD one of the lucky 10,000 approach and just think about how much time learning this will save them in other parts of their life, but sometimes it's hard.

1 - [https://www.openhousetour.ca](https://www.openhousetour.ca)

<comment><USER14> If you're struggling with that kind of support, I recommend that you start playing a game. It's called "learn something new every contact".

The rules are simple. Whenever you talk to a client you haven't spoken to before, your goal is to learn something new. It might be something new about your product/problem, but it could be completely unrelated. Hell, through the years I've learned how to make an insanely good brine for turkeys, piss off Mormons in Utah and make a killer whiskey sour.

I recommend this because at this point, that level of support you're providing is business development, so the impression you leave is very important. Clients tend to feel very awkward when they have simple problems with someone they deem an expert. And, if you can provide that level of support while seeming genuinely interested in your clients, you'll win more than you lose. Try it!! Worst case scenario, you might learn to make a turkey so good you'll get emotional thinking about it...:)

<comment><USER13> hahaha. Thanks, that's good advice. I'm not the most personable (luckily my wife is) and honestly when you put it this way it sounds so simple, but for the life of me I wonder how on earth people manage to do this without feeling scripted like "what are your interests?". How do you get to the point where you actually know enough about someone to say hey, that's something they know that I would like to learn?

<comment><USER14> Unfortunately, the shortest possible answer is really hand wavy and vague. That kind of knowledge tends to come fairly organically if you really listen to what people say and aren't afraid to share a little bit about yourself.

When you're in the early stages of a venture, ideally, you know a little bit about the person you're talking to, know a bit about the problem they're having and are genuinely interested in how they found you and if your solution is working for them. That gives you a ton of fertile ground. In this stage, I love to thank people for using my product, tell them that because my product is so new it's very important to me that all of my users are very happy, and then ask them for any feedback or advice they have. It sounds very corny and scripted (and honestly, it is), but most of the time, if my product is any good and if it solves a real problem, everyone I talk to will have something.

At that point, it's about always validating what the person says to you. It doesn't matter if you agree, if you plan to implement the feature, or if you think it is the most incredibly stupid thing you've ever heard. Someone cares enough about your product to give you some feedback! Hearing feedback is an honour and I think it should be treated as such.

If you get those two things down, you'll learn from almost everyone you talk to. Particularly those people who need a little extra help. And, when you're working with people who need a little extra help, it's good to validate them too. Maybe you have a user who has trouble with copying and pasting. That sucks, but it's also an unbelievable opportunity. As builders, we need people like that to help us escape our own little, highly technical echo chambers!

Aside from those things, it really just comes down to active listening. If you listen closely, you'll start to notice that lots of people leave little threads in their statements. They'll often leave these little threads when they're about to pause and let you talk. For example, if you ask "how are you?" someone who is really open to talking will reply, "I'm good, it's a beautiful day today." That little thread about a beautiful day opens up lots of questions. If you don't already know where they're from, you can ask. If you do know, you can confirm, "Ah, you're from Timbuktu, right?"

Also, it's important to note that this only really works if you're genuinely interested in what people are saying. A big part of the game is knowing when to stop playing. We live in a world where it's expected to be prosocial and interested in everyone around you. But honestly, there's nothing wrong with being selective in who interests you. I would caution you that if you aren't genuinely interested in what people are telling you, you need to either get genuinely interested, or you need to replace yourself with someone who is. But, there's no value judgement in that. We're all programmed differently and it's all good.

<comment><USER15> Not OP but thanks, this was helpful to me too!

</comment></comment></comment></comment></comment><comment><USER16> I'm still weeks from where I want to accept customers... and I'm getting nervous.

</comment><comment><USER17> The title is misleading. It should be "How to Get Your First Users".</comment>


Open-source clone of the Age of Empires II engine - <AUTHOR> https://github.com/SFTtech/openage <comment><USER2> As a longtime fan of Age of Empires, I have absolutely fallen in love with the open source 0ad clone.

[http://play0ad.com/](http://play0ad.com/)

The AI is surprisingly good, and the character models are as good as Age of Empires. Bonus points that it is in all major Linux distro repositories if you're one of those kinds of people (like me!).

<comment><USER3> Honest question... did it get better recently? I tried it years ago... and the AI was non existent...as in, I built up an army and went to explore, only to find my enemy had like 4 peasants.

<comment><USER2> If you watch their svn history, they consistently are chipping away at it. I simply wait (to upgrade to a new 0ad) with the latest version in each new Fedora release. It gets progressively better from an AI, music, and artwork standpoint.

0AD is definitely not the same game now as it was years ago, it is massively improved. These were both pretty big releases:

[https://play0ad.com/new-release-0-a-d- alpha-21-ulysses/](https://play0ad.com/new-release-0-a-d-alpha-21-ulysses/)

[https://play0ad.com/new-release-0-a-d- alpha-22-venustas/](https://play0ad.com/new-release-0-a-d-alpha-22-venustas/)

I find the AI to be challenging to beat on hard, but not impossible. I'll play as the Ptolemies, because I know that they were the pinnacle of the Greek Phalanx lead by none other than Alexander the Great. So I was trying to take a large group of spearman up to take over an enemy town center filled with archers but wasn't having a ton of luck. Every time my infantry would retreat, the 20 archers would come out and chase them down. When I'd turn back, the archers would head back to the town center and shred through them. My winning strategy involved staging 10 companion cavalry to the east and have the infantry attack the town center and then retreat south, drawing the archers out to try to take out the infantry. The companion cavalry rode north of the archers cutting off their retreat to the town center and let the infantry cut them down.

The newer AI will also scout out your location and attack weak spots. They'll purposefully avoid attacking through walls and lots of towers if you mistakenly leave an unprotected rear or flank that they can use to march right up and destroy your town. It is certainly more difficult now and the new graphics make it a lot of fun to play.

<comment><USER4> Speaking of AI, there's pretty interesting project which aims at creating 0AD bot that uses hierarchical planning, not just some random heuristics: [https://github.com/agentx-cgn/Hannibal](https://github.com/agentx- cgn/Hannibal)

</comment></comment></comment></comment><comment><USER5> For other AoE fans, I like this real-world map creator tool:

[https://peterolson.github.io/AOE2-Real-Map- Creator/](https://peterolson.github.io/AOE2-Real-Map-Creator/)

I've made my own custom map of Taiwan with the correct locations for gold, stone, and types of fish in the area. I plan to screen-record some famous historical events and make a video, but I'm still figuring out how to make such a video interesting and short enough to actually watch.

<comment><USER6> For what its worth I would watch just based on your description alone. May be better to just make one and get feedback than focus on making it interesting. Also, please let me know once you do. :-)

</comment></comment><comment><USER7> 0ad is another open source project. It's a full-fledged game which can be modded with your own imagery/units, etc.

[http://play0ad.com/](http://play0ad.com/)

</comment><comment><USER8> In case this wasn't posted, here is an index of all open source clones.

[https://osgameclones.com/](https://osgameclones.com/)

It doesn't list OpenAge there yet but shows 0ad instead. I wonder if we'll ever see Total War 1 clone as well as a Civ 5 clone.

<comment><USER9> Seems like OpenAge is just a clone of the engine, not a full standalone game like 0ad.

<comment><USER10> Not yet, but a full game is the plan.

</comment></comment></comment><comment><USER11> AoE2 is the one game I play regularly. It's great that this project was started, but is it still active? Did anyone manage to compile and run it, and if so, how does it feel?

Not to belittle the nice work, but I feel there was a better reason for making this clone a few years ago. There has been a "HD" version on Steam for a couple of years, which finally has good network support and most of the bugs seem ironed out, after almost 20 years! The only thing I still miss is to be able to run it on Linux...

<comment><USER12> Runs better on wine than it does on windows.

<comment><USER13> Citation needed. In my experience, running AoE2HD in Wine results in strange mouse errors at the start of a match which can ruin a game (where the screen is stuck scrolling to one side).

<comment><USER14> The mouse bug seems to be gone for me (it was mainly triggered by alt-tabbing out of the window). It still has an issue with text not being rendered properly while typing.

</comment></comment></comment></comment><comment><USER15> There's also a new Age of Empires coming out soon. You can thank Bill Gates for it:

[https://www.reddit.com/r/IAmA/comments/49jkhn/im_bill_gates_...](https://www.reddit.com/r/IAmA/comments/49jkhn/im_bill_gates_cochair_of_the_bill_melinda_gates/d0s9j8s/)

[https://www.reddit.com/r/IAmA/comments/5whpqs/im_bill_gates_...](https://www.reddit.com/r/IAmA/comments/5whpqs/im_bill_gates_cochair_of_the_bill_melinda_gates/div4w6h/?context=10000)

</comment><comment><USER16> Note that the AoE 2 community is still going strong with HAD and Voobly communities, casters like T90 and ZeroEmpires, and streamers like Viper.

There have been some epic professional games as well as community games.

It will be interesting if a similar competitive community popped up for the open source versions.

</comment><comment><USER17> Most impressive feature:

> We have an integrated terminal emulator supporting ecma-48. You can run vim > or anything else within openage. This is neat to interactively edit scripts.

it runs vim!

</comment><comment><USER18> Status Video on Youtube

[https://www.youtube.com/watch?v=FnLTS4tAJKs](https://www.youtube.com/watch?v=FnLTS4tAJKs)

</comment><comment><USER19> There is also the open source implementation of RollerCoaster Tycoon 2:

[https://github.com/OpenRCT2/OpenRCT2](https://github.com/OpenRCT2/OpenRCT2)

<comment><USER20> The approaches are dramatically different, though - this implementation seeks to discover and re-write the game logic from the outside in (black box), using reverse-engineering to understand things like the assets file formats. OpenRCT2 started as a direct translation of RCT from the original assembler into C (via Hex-Rays) and builds on the original game engine verbatim.

</comment></comment><comment><USER21> Age of empires is the only game I play on steam

<comment><USER22> Same here! Wololo.

</comment></comment><comment><USER23> I'm working on my own open-source game as a Tetris Attack clone. [https://github.com/omenking/swap-n-pop/](https://github.com/omenking/swap-n- pop/)

What I'm always surprised is the lack of tooling and test code and I'm of the belief that in the war of the clones, the ones that chooses tooling and a stack designed for larger teams, and a focus on BDD will get your project where it needs to go.

Instead of building a game, focus on building a team.

Great work on this clone so far, I was just talking top of mind.

<comment><USER24> I did not downvote you but I suspect you might have been downvoted because you "stole" someone else's thunder so I would suggest you post your clone in a, perhaps, Show HN post.

<comment><USER25> Interestingly, it's pretty common to also mention your own project in a comment, and how it's received seems to differ quite a bit based on how it was presented. If they start out with relevant comments about the current submission, a segue-way into a somewhat related project is usually taken well. If you start off with what can be taken as self promotion and take a while to get to relevant comments about the current submission (or never do), it's not received well.

In this case, I'm actually surprised that it was downvoted. After the initial line with a link, it's all fairly general and about clone projects in general, which makes that line read as presenting bon fides and not self promotion when the comment is interpreted as a whole.

</comment></comment></comment><comment><USER26> Why use SDL2 for input handling when you have Qt5?

<comment><USER27> Isn't sdl2 a lot smaller than qt5?

<comment><USER26> They list both as a dependency, that's why I mentioned it.

</comment></comment></comment><comment><USER28> I am curious how is this not a copyright infringement?

<comment><USER29> No code or artwork has been copied from the original game, so why would it be copyright infringement?

</comment></comment><comment><USER30> This is awesome if it means being able to play AOE2 or a clone on Linux.

I'm not sure I understand if engine means playable game..?

<comment><USER31> Not really playable. See status here:

[https://github.com/SFTtech/openage/blob/master/doc/status.md](https://github.com/SFTtech/openage/blob/master/doc/status.md)

<comment><USER30> Thanks.

</comment></comment></comment><comment><USER18> AoE II for Linux :D

Hope it will be in a playable state soon.

<comment><USER32> 0ad is playable today. On Fedora try

        dnf install 0ad

</comment></comment><comment><USER33> Interesting, what's made them choose to do this with AoE II rather than AoE III? Is II more popular?

<comment><USER23> I think the best in the series on AOM, felt like a streamlined version, though that game requires no cloning.

I only have faint memories of AoE II and at the time never had a powerful enough computer for AoE III.

I can never get the iconic AoE theme out of my head.

</comment></comment><comment><USER34> WTF

Contributing: Being typical computer science students, we hate people. Please don't contact us. Nobody likes Age of Empires anyway. None of you is interested in making openage more awesome anyway. We don't want a community. Don't even think about trying to help.

Guidelines: No bug reports or feature requests, the game is perfect as is. Don't try to fix any bugs, see above. Don't implement any features, your code is crap. Don't even think about sending a pull request. Please ignore the easy tasks that could just be done. Absolutely never ever participate in this boring community. Don't note the irony, you idiot. To prevent accidental violation of one of those guidelines, you should never

<comment><USER35> It's a joke. It's obvious that they want people to contribute, as this follows with:

\---

To prevent accidental violation of one of those guidelines, you should never

* learn git

* fork the repo

* learn python

* learn c++14

* read the code and documentation

* contribute anything to the code

* contact us

cheers, happy hecking.

\---

The contribution guide in general is pretty well written and welcoming.

<comment><USER36> Also, "Don't note the irony, you idiot." directly above that.

<comment><USER37> And for those Vulcans that are still confused, this is Morrisette-level irony.

<comment><USER38> Is it though? I think it's not the actually-just-a-coincidence type of 'irony' from her song, but rather actual 'verbal irony', [https://en.wikipedia.org/wiki/Irony#Verbal_irony](https://en.wikipedia.org/wiki/Irony#Verbal_irony).

</comment></comment></comment></comment></comment><comment><USER39> Why C++ instead of a higher level language like Python? The developers could focus more on game functionality than C++ bugs and cross platform issues. Performance should not be a big concern for running an old game on modern hardware.

<comment><USER40> Rule of thumb suggests that implementing AoE with Python today probably means PyAge2 runs about as well on a 4.5 GHz CPU as AoE2 did on a 266 MHz Pentium II. (not that well)

<comment><USER41> And with C++14 the stdlib provides out of the box alternatives for most syscalls. No cross platform woes needed.

Also, they do use Python. One of it's advantage is that it's easy to integrate with native code. So you should implement the hot parts in C++.</comment></comment></comment>


Ask HN: Why hasn't brain inspired AI architecture succeeded? - <AUTHOR> <comment><USER2> Why do you say it hasn't? I'd say if you want to discuss this, you should first define "brain inspired AI architecure" and also define "success".

By some standards deep learning _is_ a "brain inspired" architecture and that has, in turn, been wildly successful by some standards of "success". But since you're asking, I assume you mean something else...

<comment><AUTHOR> Yeah that's a good point, I mean't more rigorously inspired than traditional deep learning, specifically referring to recursive cortical networks, schema networks, and modular neural networks. I'll refine further and be more on the ball about fostering discussion when I raise the topic in the future

<comment><USER2> Interesting... this is like the second time in the past few days I've heard someone mention modular neural networks. I don't know much about those, but plan to read up on them soon.

What do you think about Hinton's CapsuleNets work?</comment></comment></comment>


"A Honeypot for Assholes": Inside Twitter's 10-Year Failure to Stop Harassment - <AUTHOR> https://www.buzzfeed.com/charliewarzel/a-honeypot-for-assholes-inside-twitters-10-year-failure-to-s?utm_term=.cf9lYYV9zg#.slYMPPojzG <comment><USER2> The whole "dedication to free speech" mantra is cute, but ultimately just reeks of a failed bet on how to run the company.

From a technical perspective, letting essentially anyone say anything is easier to handle. The engineering resources that would otherwise go towards advanced content filtering and detection, etc can now just focus on making the platform scale. That works out well when a company is growing like crazy in the early days.

From a business perspective, the hate-spewing users are "really engaged with the product." Having a lot of users in this category is a great thing to tell investors. Also, the growth from these users is something investors like, too. So it's also a win from a business perspective.

I'm guessing that Twitter's leadership made a decision early on. Something along the lines of "let's go with the free speech thing for now. It lends itself to efficient allocation of engineering resources and improving key metrics." When you're growing as fast as Twitter in the early days, it's not necessarily a bad choice. However, the current growth stagnation and other negative issues surrounding the company is really starting to expose the downsides of that haphazard decision.

</comment><comment><USER3> There should be a separate domain for buzzfeed's long form articles. I suppose I could make an anti-listicle filter but having it be explicit would be nicer.

<comment><USER4> They should, at least, rebrand themselves. "BuzzFeed" toxicity is so high, I can't see why they wouldn't get a massive malus for it.

</comment></comment><comment><USER5> OT: There are some beeautiful visuals/illustrations around the text

</comment><comment><USER6> Twitter is a cesspool, but isn't an open, public conversation between everyone in the world pretty much guaranteed to be a cesspool? I don't see how you can stop that from happening without compromising the principle of Twitter itself.

You take on risks when you start announcing your private thoughts to the widest possible public audience. Those risks go along with being any kind of public creator. Other than because no one would really be interested in my tweets anyway, this is precisely the reason why myself and others exercise our free choice not to tweet. We don't want a trail of statements for which we are publically held to account, even if by harassers, racists and misogynists, if we can't - and shouldn't - control the audience for those tweets. If you want a limited, curated audience, go somewhere else.

<comment><USER7> Is this forum a cesspool? (No.) Is it an open public conversation by anyone in the world? (Yes.)

You can have conversations without it becoming a racist, bigoted mess.

<comment><USER8> People get banned from here all the time tho and there's plenty of racist garbage that gets posted.

<comment><USER9> Exactly. HN is a very good definition of a community that's maintained a significant standard in good communication by using relatively basic tools and quality community moderation. Twitter could have been this. But they chose to believe that no moderation would be just fine.

<comment><USER10> The post count here is significantly lower than Twitter. I shudder to think how many moderators it would take to administer Twitter.

You might think that the downvote mechanism here helps somewhat, and it does, but on any large community with voting such as Reddit the ability to downvote turns the community into an echo chamber where only the largest group gets a say and any dissenting voice is vanished. I dare say we see the same thing here on HN.

</comment></comment></comment></comment></comment><comment><USER11> The omissions from this article are kind of strange.

For example, it somehow manages to ignore the many harassment campaigns against various white people (e.g. Justine Sacco, Pax Dickinson, Brandon Eich, Milo) who's politics don't conform (or based on a single tweet, appear not to conform) to what is acceptable.

Or it brings up Leslie Jones, but then completely ignores all her racist tweets and calls for follower to harass others: [http://www.breitbart.com/tech/2016/07/20/double-standards- le...](http://www.breitbart.com/tech/2016/07/20/double-standards-leslie-jones- racist-twitter-history/)

That sure is weird.

[edit: clarified my point better.]

<comment><USER12> This is a very disingenuous comment. You know well why the article left out Milo Yiannopoulos and Pax Dicksonson: they're both prominent racist trolls. You included Justine Sacco and Brandon Eich deliberately in order to draw an equivalence between them and Yionnopoulous. Obviously, that equivalence is false. And you conned people, me included, into reading _the dumbest Breitbart article ever created_. Mercy, mercy, Leslie Jones used the words "white people"! How-ever does Twitter allow her to keep posting?

Who are you trying to kid? More and more, your comments on HN are becoming a parody of themselves. You have real arguments to make. I don't _like_ most of them, but at least I can respect them. This, though, is more horseshit.

<comment><USER13> Targeted abuse goes both ways:

[https://twitter.com/lesdoggg/status/755218642674020352](https://twitter.com/lesdoggg/status/755218642674020352)

<comment><USER14> For reference, the tweet says:

> @whitebecky1776 bitch I want to tell you about your self but I'm gonna let > everybody else do it I'm gonna retweet your hate!! Get her!!

And the Twitter rules say:

[https://support.twitter.com/articles/18311](https://support.twitter.com/articles/18311)

> Harassment: You may not incite or engage in the targeted abuse or harassment > of others. Some of the factors that we may consider when evaluating abusive > behavior include:

> ...

> if the reported account is inciting others to harass another account;

> ...

Just FYI.

</comment></comment></comment></comment><comment><USER15> I always thought Ashley Judd was the first big harassment story on Twitter. Here is her account of it. Though I remember it happening earlier than 2015. Maybe there are multiple incidents.

[https://mic.com/articles/113226/forget-your-team-your- online...](https://mic.com/articles/113226/forget-your-team-your-online- violence-toward-girls-and-women-is-what-can-kiss-my-ass#.Pmx00Qq6t)

</comment><comment><USER16> If drawing the line on what is and isn't harassment is subjective, perhaps they should focus on building better mechanisms for individuals to take filtering / blocking into their own hands? One could argue that Twitter has these features already, but apparently the "privileged class" (celebrities) are incapable of leveraging them?

<comment><USER10> I don't use Twitter, never have, but I don't understand why the platform doesn't have a whitelist mode, where only those people you've added to a list can message you. Seems like it would sort the problem for good, but I'm probably missing something.

<comment><USER17> I'm in the same boat as you on Twitter usage. But I suspect it's because being able to talk at anybody, including celebrities, is part of the appeal of the platform. The whitelisting mode you suggested makes it more like a one-way broadcast - you can see what people are saying but not join in.

</comment></comment></comment><comment><USER18> Depends on what people decide IS harassment, in this survey [http://www.bbc.co.uk/news/uk-37025554](http://www.bbc.co.uk/news/uk-37025554) 52% of women said unwelcome jokes heard years ago amounted to harassment.

who objectively decides what is and isn't?

<comment><USER9> I think the people getting abused have a fair amount of say in what's abusive and what's not. Working conditions/scenarios from years ago might be considered unwelcome today. That doesn't make my negative feeling towards a "work 8 hours a day for 35 years in one company and retire" scenario invalid. Your question however IS the problem. Sure there are a lot of messages that straddle a fine line between abuse, jokes, and not at all abuse. But people have quite collectively agreed that rape threats are a form of abuse. That doxxing is a form of abuse. But the attitude towards even these kinds of obvious forms of abuse has remained flippant at best because instead of catching the low hanging fruit, people counter with bike shedding style questions of "is it really abuse?". The problem here honestly is a simple case of not wanting to listen hard enough.

<comment><USER11> _I think the people getting abused have a fair amount of say in what 's abusive and what's not._

This is circular reasoning.

If I can define X as abusive (where X is something I don't like), then I am a person getting abused. So now that allows me to define whatever I want as abusive?

<comment><USER17> That's a near-perfect example of what the GP was referring to with "...instead of catching the low hanging fruit, people counter with bike shedding style questions of 'is it really abuse?'"

And while I get your point about circularity, it pretty much has to be that way. For example, if I threatened to stab a random person with a syringe, that would be abusive. If I threatened to stab my brother with a syringe, that's an inside joke from when we used to play "Battlefield Vietnam" together.

Which is pretty much what the article was getting at when they talked about context mattering more than content.

<comment><USER11> _That 's a near-perfect example of what the GP was referring to with "...instead of catching the low hanging fruit, people counter with bike shedding style questions of 'is it really abuse?'"_

Ok, in that case lets also catch the low hanging fruit of black men raping white women. And if you say "a black man asking out a girl who doesn't like him isn't rape" then you are guilty of bikeshedding. <\- Spot the fallacy yet?

If circularity is valid then as a victim I define names that start with "brei" to be harassment. You can tell I'm a victim because someone with a name starting with "brei" replied to me, which makes this valid. <\- Spot the fallacy yet?

Consider the possibility that if you can't prove your point without deliberately resorting to logical fallacies, that your point might be wrong.

<comment><USER17> Yes, clearly one can construct ridiculous examples. On the other hand, one can also ignore clearly valid cases while trying to construct the perfect solution. Sometimes the real world involves solutions that are merely acceptable. Or even individual judgement calls - hence why we have judges and juries.

But since you seem to think that there is a fully-cohesive, non-circular, objective way to judge what is harassment or abuse, please enlighten me as to what it is.

If you fail to do so, then somebody will probably rape and kill your entire family. <\-- Not abusive, because there isn't a peer-reviewed Theory of Abuse available.

edit: Just for the hard-of-sarcasm, the last bit is to illustrate the ridiculousness of the argument, not an actual threat.

</comment></comment></comment></comment></comment></comment><comment><USER19> The internet will always have trolls and always had trolls. Twitter as a platform doesn't do anything differently than the old IIRCs or forums when it comes to this.

It's that whole people behind an anonymous screen are assholes because they can thing.

<comment><USER20> > The internet will always have trolls and always had trolls.

Humanity has always lived on subsistence and never flown, until it fixed those things.

> Twitter as a platform doesn't do anything differently than the old IIRCs or > forums when it comes to this.

The vast majority of forums I've used had responsive moderators and the ability to remove trolls (including correlating concurrent or sequential sockpuppets and reapplying sanctions on new accounts). IRC tends to be more spartan, but even there you could require authentication, autokick abusers and ban IPs.

Of course both were intended as _communities_ (of sorts) not trying to sell their growth, so removing a bunch of assholes wasn't considered an issue by anyone.</comment></comment>


Nothing is cheaper than proof-of-work - <AUTHOR> http://www.truthcoin.info/blog/pow-cheapest/#is-a-work-independent-protocol-possible <comment><USER2> This article makes a case that the creation of new coins (or blockchains) is inherently 100% wasteful. This is to some extent talking past the actual advocates of proof of stake systems, who claim that PoS can provide _security_ , not new coin distribution, at a lower total cost.</comment>


Ask HN: Any good free alternatives to meetup.com? - <AUTHOR> I'm, looking to start a tech meetup but put off by the steep prices of meetup.com <comment><USER2> [http://lanyrd.com/](http://lanyrd.com/) has less features but it's established. (The next event we're running in London,England as example: [http://lanyrd.com/2016/geomob-november/](http://lanyrd.com/2016/geomob- november/))

</comment><comment><USER3> Facebook Events?</comment>


What's New in Sinatra 1.2? - <AUTHOR> http://www.sinatrarb.com/2011/03/03/sinatra-1.2.0.html

<comment><USER2> PS: There is a pretty nice little MVC framework built on Sinatra called Padrino. <http://www.padrinorb.com/>

</comment><comment><USER3> I'd really like to figure out the best way to communicate what things like sinatra are compared to stuff like rails, django, spring etc.

Is it a mini-framework? un-framework? lightweight framework? Please folks, give me some good ideas for the best quick term to capture what sintra and its ilk are.

By its ilk, I mean 'frameworks' that really do 1 or 2 things for you, do them well ( like routing ) and get out of your way. Others I've used that fit into the same idea... compojure & seaside...

So please, terminology suggestions?

<comment><USER4> A couple similar frameworks -- Flask [1] and Tir [2] -- use the term microframework or micro-framework.

[1] <http://flask.pocoo.org/> [2] <http://sheddingbikes.com/posts/1289384533.html>

<comment><USER5> It was with Camping (<http://camping.rubyforge.org/>) that i first came across the term "web microframework" and its probable that all subsequent usage stems from this?

However I believe the emphasis of _microframework_ that Camping was trying to put across was more on its code size which came in at or under 4K [1]. So perhaps frameworks which also accomplish a small code footprint, for eg. Squatting (<http://search.cpan.org/dist/Squatting/>), are best called _microframeworks_ [2]

However happy to use _microframework_ for Sinatra, Dancer, Flask, etc in lieu for something better? ( _nepenthe_ suggestion in the comments of "convenience framework" seems good to me - <http://news.ycombinator.com/item?id=2286376>).

[1] [https://github.com/camping/camping/blob/master/lib/camping.r...](https://github.com/camping/camping/blob/master/lib/camping.rb)

[2] [https://github.com/beppu/squatting/blob/master/lib/squatting...](https://github.com/beppu/squatting/blob/master/lib/squatting.pl)

</comment></comment></comment><comment><USER6> Just gets better and better with each release.

<comment><USER7> Just like Sinatra himself.

</comment></comment><comment><USER8> Sinatra's sweet spot is in light weight apps and services. It's simpler than Rails and gives you more help than pure Rack when you want to prototype a feature, or build services for a SOA based application.

See <http://neovigator.heroku.com> for an example sinatra app.</comment>


Six Millennials make millions. So why do they share a house? - <AUTHOR> https://m.sfgate.com/business/article/These-six-Millennials-make-millions-So-why-do-14074341.php <comment><USER2> I think I'm going to be sick

<comment><USER3> Please take care of yourself, but could you please stop posting unsubstantive comments to Hacker News?</comment></comment>


ASK HN: Why are so many IP's text based? - <AUTHOR> <comment><USER2> As you can see clearly from the 5 previous answers, the reason why is obvious.

<comment><AUTHOR> I was looking at this from more of an 'efficiency' perspective actually. Text- based protocols have a bit of an overhead as they require sending more data to transmit the same amount of information. So what benefits outweigh this?

After a bit of digging, it does appear my question itself was incorrectly phrased. But it seems to be that the majority of internet traffic use text based protocols. There are many more binary protocols than text but more text traffic than binary. Thus most of the successful protocols on the internet are text based. Except for a small number of applications (bittorrent is one example) binary protocols tend to die.

</comment></comment><comment><USER3> What do you mean by "text based IPs"?

<comment><AUTHOR> text-based vs binary. So most of the characters used in the IP are between 0x20 (space) and 0x7E (~), opposed to transmitting binary over the connection.

<comment><USER4> Only HTTP is text based. TCP, IP, and link-layer protocols are binary.

HTTP is text based because it is a protocol for transferring (hyper)text and so was intended to be human readable like hypertext is.</comment></comment></comment>


Arm's New Cortex-M55 Breathes Helium - <AUTHOR> https://fuse.wikichip.org/news/3319/arms-new-cortex-m55-breathes-helium/ <comment><USER2> Clickbait title.

Advice to change it to reflect that Helium is just a marketing term for some new instruction set they have .</comment>


Ask HN: Thinking in terms of customers vs users? - <AUTHOR>

How does this affect the way a startup approaches their target market? <comment><USER2> For my own work, there's an explicit distinction between customer and user. Design the software for the user, design the marketing for the customer.

For a more radical perspective, consider the old saw "You aren't [Google|Facebook|Yahoo]'s customer, you're their product." The customer is the one who pays for the service in cash.

</comment><comment><USER3> Customers pay. Users might not pay.</comment>


Slack comes to Linux as a snap - <AUTHOR> https://techcrunch.com/2018/01/18/slack-comes-to-linux-as-a-snap/ <comment><USER2> « this will open Slack up to users of Linux-based services like ArchLinux, OpenSUSE, Solus, Debian, KDE Neon and others. » I don't get it. I use the slack app on my Debian for almost a year. Am I missing something ?

<comment><USER3> It means they're probably tired of maintaining standards such that their application can run on multiple distros, and have decided to shove it in a container.

I love the idea of snaps, but good grief they sometimes have really backwards build processes -- start with a traditional rootfs, install packages, delete cruft (pray you didn't delete the wrong cruft), export and call it a day.

<comment><USER4> I really sympathize with this view. At ZeroTier we try to support multiple distributions and versions of distributions going back quite a while and it is hell on wheels. It's so tempting to just build everything as a static binary and let the user figure out how to support the three different init systems that can each be configured in seven different ways.

Linux has far too many distributions. They really aren't that different, so I have a hard time understanding why they exist. The community as a whole would benefit hugely if e.g. Debian and CentOS/RedHat/Fedora merged, but I understand that's not going to happen for stupid political reasons.

<comment><USER5> _> stupid political reasons_

TBH I wouldn't call them "stupid political reasons". Debian is basically the institutional ONG of the Linux world; RedHat is a public company; they have wildly different targets and objectives. This is not "stupid". It's like saying "Firefox and Edge should merge, but it won't happen for stupid political reasons" \- no, it's because they are very different things with very different aims.

Anyway, I'm curious: are you considering Snap for your products then? Sounds like a prime candidate. Although tbf I don't really know how it handles init systems.

<comment><USER4> I really don't want to use snap since tarring up containers is a hideous hack, but then again we have a "curl | bash" script which is also an evil hack.

<comment><USER5> Apart from the security differences, which are quite stark, the main advantage that I see is that, with Snap, the distributions take on a bit (or even a lot) of the responsibility for making a product work consistently.

With a bash script, you're always on your own. That's very powerful, of course, but it's usually more of a burden. It's a bit like using a package manager vs manually installing tarballs.

</comment></comment></comment></comment></comment></comment><comment><USER6> I just run it in the browser (on Windows) ... the slack app has the tendency to consume ever larger amounts of RAM if I let it run for a while. I have the feeling they just append each new message and never clear old messages out of memory, but I never cared enough to actually check. Just banning it back into the browser solved it.

<comment><USER7> [https://slack.engineering/introducing-electron-to-the- window...](https://slack.engineering/introducing-electron-to-the-windows- runtime-4fa789b93d90)

Even when it's the "native" app, it's kind of still running in a browser (it uses Electron).

</comment></comment><comment><USER8> For you Flatpak users out there Slack is also available on Flathub as well.

[https://flathub.org/apps.html](https://flathub.org/apps.html)

<comment><USER9> What exactly is Flatpak?

<comment><USER10> [https://en.wikipedia.org/wiki/Flatpak](https://en.wikipedia.org/wiki/Flatpak)

</comment></comment></comment><comment><USER11> It's still a 150MB web-browser + attached web app, right?

<comment><USER8> Well yeah, it's not like how it's packaged changed the underlying design.

If you want a lightweight version of the slack client and don't fell like using the IRC or XMPP bridges you can use Epiphany (or Chromium) to install the website an an 'App'.

<comment><USER12> I find just pinning the tab (right-click on tab, select Pin Tab) on Firefox does what I need it to do. I mention this because I suspect many people are unaware the feature exists.

Pinning a tab gives it permanent priority on the left-hand side of the tab list, and elides the title from the tab, so it is just the favicon. It also blocks CTRL-w from closing the tab; you have to actually right-click and either unpin or close the tab. That may sound trivial, but was the biggest problem I had running it in the browser before, it got caught in my periodic tab cleanups accidentally. Now I never accidentally close it.

</comment></comment></comment><comment><USER13> Slack's UI makes me insane. As a snap, or otherwise the lack of customizability, lack of minimalism and inability to size the UI to my liking makes me hate using it. I'm stuck with it and it feels like chat prison.

<comment><USER14> There's a lot of third party command line clients :

[https://github.com/evanyeung/terminal- slack](https://github.com/evanyeung/terminal-slack)

[https://github.com/regisb/slack-cli](https://github.com/regisb/slack-cli)

[https://github.com/juanpabloaj/slacker- cli](https://github.com/juanpabloaj/slacker-cli)

etc.

<comment><USER15> snap install slack-term ;)

</comment></comment></comment><comment><USER16> This is the first I'm hearing about Snap, what do you guys think of that as a platform?

<comment><USER5> I like it quite a bit, even applied for the related dev-advocacy job (and was resoundingly ignored; rightly so, I might add). It removes the complexity layer of having to deal with multiple packaging systems, and it isolates the app at the user level which helps with dependencies.

The only issue I see, really, is that it does not appeal to the traditional Linux userbase, the greybeards and neckbeards who are used to all the packaging esoterica. It's a user-friendly concept that happens to be very developer-friendly too, but has no appeal for the sysadmin crew, which is still the majority in Linux land. So it risks being ignored.

</comment></comment><comment><USER17> I wasn't able to get it working through software center but this worked.

> $ sudo snap install slack --classic

<comment><USER15> Yeah, that bug is being fixed and working through the release process right now.

</comment></comment><comment><USER18> Firefox and Slack are only on Snap and not on Flatpak. Is there a reason why this is happening ?

<comment><USER19> There has been a Firefox Flatpak for a long time: [https://firefox- flatpak.mojefedora.cz/](https://firefox-flatpak.mojefedora.cz/)

And there has been discussions about getting an official one from Mozilla.

<comment><USER20> Any plans on submitting this to flathub?

<comment><USER19> No, Firefox is a security sensitive project so Flathub wants Mozilla to be the official maintainer of it.

<comment><USER20> That's a great policy, thanks!

</comment></comment></comment></comment></comment><comment><USER21> I'd like to hear from anyone that is using snaps. I'm currently using Ubuntu 17.10 and have heard of them but haven't noticed them anywhere. Is it something I should consider using? Generally happy with slack in the browser currently.

<comment><USER22> There's a "bug" which requires a Ubuntu account to load "snaps". It hasn't been fixed, despite claims that a Ubuntu account is unnecessary for that function.

<comment><USER5> Uhm, i never had an Ubuntu account and am pretty sure I tried a few snaps last time I checked out Ubuntu.

<comment><USER19> The software center has the bug, the cli tool works fine.

<comment><USER15> Not any more.

</comment></comment></comment></comment></comment><comment><USER23> I wonder if this will give them some impetus to get calling working properly on Linux?

<comment><USER24> I use calling in Linux all the time, including screen sharing. It seems to work fine. Korora on X1 Carbon 5G.

<comment><USER25> I use calling too and it works fairly well. However when sharing my screen i have to share "all my monitors" does anyone know why it's done this way?

</comment></comment></comment><comment><USER26> 1) Wait for browsers to implement adding PWAs to desktop 2) Write once, run everywhere 3) Everyone is happy

</comment><comment><USER27> I've been using a Slack flatpak for months, from flathub.org

</comment><comment><USER28> is this like nix?</comment>


Knuth Is My Homebody T-Shirt - <AUTHOR> http://geekz.co.uk/shop/store/show/knuth-tshirt

<comment><USER2> "Homeboy", not "Homebody". It makes a difference.</comment>


The Rural/Urban Economic Divide in America in Six Charts - <AUTHOR> https://theconversation.com/six-charts-that-illustrate-the-divide-between-rural-and-urban-america-72934 <comment><USER2> With respect to disability rise in the article, NPR/Planet Money discusses the use of disability benefits as a defacto workaround for inadequate welfare/unemployment benefits.

[http://apps.npr.org/unfit-for-work/](http://apps.npr.org/unfit-for-work/)</comment>


Extracting city blocks from OpenStreetMap data - <AUTHOR> https://peteris.rocks/blog/openstreetmap-city-blocks-as-geojson-polygons/ <comment><USER3> Always good to see geospatial analysis, especially with the toolchain available in Python, these days!

One of the downsides of forming polygon from line segments in this way is that it implicitly assumes all lines have a vertex at the intersection of another line.

For example, something like this would fail ("o" represents a vertex):

        o      o  o
         \      \/
          \     /\
           \   /  \   o
            \ /    \ /
             /      /
            / \    / \
           o   \  /   \
                \/     \
                /\      o
               /  \
              o    \
                    o

You can handle this in a couple of ways:

1) Intersect the lines before-hand, ensuring that you wind up with a vertex at every intersection. (In shapely's case, you'd call `shapely.ops.cascaded_union(lines)` before applying `polygonize`.)

2) Cut a bounding polygon with the lines, rather than forming polygons from individual line segments.

The second method has the advantage of ensuring that everything inside of the bounding polygon is split up into smaller, block-level polygons. Usually this is what you want, though for something like city blocks, you'd need to filter out non-urban areas (e.g. water).

<comment><USER4> What about bridges and tunnels? It seems like an ideal (or idealistic) solution is to clean up the source data to include intersections when there are intersections so they don't have to be inferred. Is that impractical or would it explode the size of the dataset?

<comment><USER3> Bridges and tunnels are still represented as linear features in most road datasets. In good ones, there's an attribute to mark it as a bridge or tunnel, and you can choose to use them or not.

Including intersections wouldn't significantly change the size of the dataset, but that type of clean-up is best done as a pre-analysis step. There's no good reason to do it in the "raw" data.

Furthermore, it's dependent on the projection/etc that you do it in. The intersection of two lines in lat/long space is not at the same point as the intersection of two lines in another lat/long space with a different datum, and it's not the same as the intersection in a projected coordinate system.

Ideally, you'd only include the intersection if you've actually measured it at that location. It's best to leave the observations as observations and try not to alter them too much.

At any rate, by the time you're analyzing the data, you've already made the type of assumptions about cartesian vs. spherical vs. real space that I'm referring to above. Therefore, it's usually a good idea to defer cleanup that's specific to a particular operation (this one is) until you're doing that operation.

</comment></comment></comment><comment><USER5> There's also the tag place=city_block [1] which may be useful depending on its coverage but which has the advantage of being explicitly assigned by a human.

I've always thought of city blocks as an anti-pattern in urban layout e.g. exploring New York on foot for the first time I tried 'using my nose' to find interesting places but had the problem that I got zero incremental information until the next intersection at which point the large block size meant it was too far to turn back.

I prefer to live in cities for which the concept of a 'block' has less relevance, and I'd caution against trying to 'blockify' cities worldwide.

[1] [http://wiki.openstreetmap.org/wiki/Key:place](http://wiki.openstreetmap.org/wiki/Key:place)

</comment><comment><USER6> I have to keep trying to open those mapbox vector tiles. Zipped protocol buffers in a sqlite file. If you want to handle a lot of geo data, you can't keep using text. Although I wonder if protocol buffer+sqlite is really a good idea.

<comment><USER7> The sqlite is only storage server-side. Otherwise you would have bazillion of small files in your filesystem and they mostly do not handle that well. (Speaking of experience of having 800k tiles in a single NTFS directory - <USER2> was not pretty).

When serving the tiles over http, the only tiles themselves are served, not the entire sqlite database.

This was actually pioneered in the era of raster tiles - pngs/jpgs in the sqlite db. Vector tiles just "inherited" that.

<comment><USER6> Do you know a vector format that is more adequate?

<comment><USER7> No; however there are not many vector tile formats publicly defined. MVT is good at what it does.

The generic vector files used in GIS (shapefiles, DGN, KML, GML etc) are not a good fit for tiles - they describe a specific classes of features and do not optimize for tiling (i.e. you must always parse the entire files without regards what extents you are really interested in) - which is fine for generic GIS usage, but not for end-user vector maps.

</comment></comment></comment></comment><comment><USER8> Looking at the visualizations provide I don't see a visual proof that the code is able to extract city blocks; by city block, I mean as defined by Wikipedia here: [https://en.m.wikipedia.org/wiki/City_block](https://en.m.wikipedia.org/wiki/City_block)

Proof might be an interactive map that shows the city block of a selected area in NYC.

Is there a visual proof in the walkthrough I'm not seeing?

<comment><AUTHOR> Data from [https://mapzen.com/data/metro-extracts/metro/brooklyn_new- yo...](https://mapzen.com/data/metro-extracts/metro/brooklyn_new-york/)

I followed my instructions in the post (except I had to use encoding='iso-8859-1' instead of utf-8)

I cropped the map a little.

Generated file [https://gist.github.com/pdonald/223e42b491eb42ba99b8e10ef1ae...](https://gist.github.com/pdonald/223e42b491eb42ba99b8e10ef1ae2072)

Interactive and clickable [http://bl.ocks.org/anonymous/raw/d62bfd592234ed71d24bfd6f264...](http://bl.ocks.org/anonymous/raw/d62bfd592234ed71d24bfd6f264cc22b/)

You can also go to [http://geojson.io](http://geojson.io) and load the generated file for more interactivity (select, delete, add your own polygons, etc.) or open it in QGIS.

In the Results section I had a screenshot of the generated polygons in both QGIS and geojson.io (polygons are separated by thick black lines and their area is colored gray).

<comment><USER8> Reluctant to respond, since it's clear that bit of more effort went into your comment than mine.

Basically for me when I click the interactive map I get a response, which is a pinned blank text-box with a x to close it. Thing is that I'm unable see that a city block is highlighted via a click; the text box simple appears where I click, unless it's outside the targeted area; for example, in the river.

Looking at the raw JSON it does appear the block are extracted.

So, putting aside "seeing" it, appears you're confirming it extracts single blocks as objects and isn't doing something else like if two blocks are attached, they're not sharing the path that's between them.

</comment></comment></comment><comment><USER9> Nice, could you try it with an irregular city? Like Rome?

thx

<comment><AUTHOR> Data taken from [https://mapzen.com/data/metro- extracts/metro/rome_italy/](https://mapzen.com/data/metro- extracts/metro/rome_italy/)

Generated file (cropped) [https://gist.github.com/pdonald/dfeee5213c8c5379f7b421f9ad5f...](https://gist.github.com/pdonald/dfeee5213c8c5379f7b421f9ad5f8b3c)

<comment><USER9> here you have the problem. You see? They are not correctly detected [http://imgur.com/iGLT5Ea](http://imgur.com/iGLT5Ea)

<comment><AUTHOR> Yes, to detect them I would also have to include pedestrian paths, service roads and other smaller roads. The solution is not perfect but good enough for the most part.</comment></comment></comment></comment>


6 ways on how to build brand and brand awareness - <AUTHOR> https://brandcloud.pro/blog-en/6-simple-steps-how-to-increase-brand-awareness <comment><AUTHOR> In this text there are six easy ways on how to work on your brand and how o widen information about your brand, how to increase brand awareness and also few handy links that will give you advice.</comment>