HNHacker News
TopNewBestAskShowJobs

brandonbloom

1,965 karma · joined May 16, 2013

brandon@deref.io

http://www.brandonbloom.name

https://github.com/brandonbloom

https://twitter.com/BrandonBloom

http://www.linkedin.com/in/brandondbloom/

Old account: https://news.ycombinator.com/threads?id=snprbob86

submissionscomments
brandonbloom··on The Rust Platform
String processing is never simple. Simply identifying "what is whitespace?" is a big undertaking in Unicode.

Lua's philosophy seems to be to include the absolute minimum that is unacceptably painful to omit. This is a perfectly reasonable tradeoff for Lua's primary use case: embedding.

With respect to strings in particular, most systems that Lua is embedded in has its own string type, or inherits one from a framework. This is an unfortunate reality of the C/C++ world.

Returning to my point about language standard libraries: The lack of a traditional "standard library" is a feature for Lua, but only because Lua has a strong FFI and C API that acts as a "bring your own standard library" mechanism. It's less about needing a standard library, and more about admitting a language is only one piece of the puzzle. For a language to flourish, you need to have some story for interfacing with the rest of the world in a rich way.

brandonbloom··on The Rust Platform
My point is that most languages are totally useless on their own. JavaScript the _language_ doesn't offer any FFI or other mechanism to call outside services. Without a browser or something like Node's libuv, JavaScript wouldn't be useful at all. The capabilities provided in the box are part of the language in terms of what actually matters in motivating people to choose to use the language, no matter what form those capabilities come in.
brandonbloom··on The Rust Platform
You don't consider the dynamic, rich document presentation engine that is HTML to be a standard "library"? Seems like it is to me.
brandonbloom··on The Rust Platform
You were being down voted, maybe for perceived snark, but I think you raise an interesting point.

To me, C did have a standard library: Unix. It's a runtime system too! Due to the nature of the original C bootstrapping process it just happens to be possible to remove this standard library, and Windows was evidence of this.

There is another interesting potential counter example: Lua. It's minimalistic standard library is part of what makes it so attractive for embedding, eg. in game engines. However, Lua's embedding API is so good, you could almost say that it comes with a large standard library too: Your existing C code!

I guess my larger point is that languages rarely are able to stand completely on their own. They need some sort of valuable body of code to justify people to choose the language and libraries together. It might have been the case 40 years ago that you'd reasonably choose to build something "from scratch", but today, if you start on an island, you need to build a bridge, lest you remain on an island forever. Better to start on the mainland.

It's one thing to build a layered system with a small core. It's another thing to completely ignore the fact that the libraries and community _are_ the language, in the only ways that actually matter.

brandonbloom··on Master Plan, Part Deux
1) It appears that Musk genuinely believes that he is acting as a fiduciary with _long term_ outlook. If the investors don't like the time scale, they can put their money somewhere else. Fuck 'em.

2) In most cases, "formality" and "rigor" only works to mask unfortunate realities and incompetence. Being plain spoken need not imply ignorance nor thoughtlessness. I may not be a sophisticated investor, but Musk's ability to so clearly outline the plan (and proven track record of executing such plans!) gives me great confidence.

3) I view the entertainment and excitement that Musk provides is a small, but welcome dividend that I'm happy to share with non-investors alike. I feel sad for you that you can't or won't appreciate it.

brandonbloom··on Master Plan, Part Deux
It's not clear to me either, but he also wrote "it will probably make sense to shrink the size of buses", so I think the implication is that one bus will become many individual cars with traditional doors.
brandonbloom··on Microsoft REST API Guidelines
I agree with tracker1 about a top-level object with data+error keys. Always useful to have an "open" / "extensible" object at the top, so you can add extra stuff as needed. Pagination is a classic example, but another one is debug data, such as profiler timings.

I'm not opposed to having meaningful status codes, but I am opposed to 1) overdoing it and 2) omitting success/failure from the body. The only useful status code distinctions are the ones that browsers respect: success vs failure, redirects, etc. Differentiating 200 OK vs 201 Created, for example, causes nothing but headaches. What would I do differently given that distinct information? What if I do a POST to create an get a 200 when I normally expect a 201? Is that suddenly now a failure?

For API use cases, I only use 200 (success), 400 ("you screwed up"), and 500 ("we screwed up"). For HTML responses, I also use whatever 3xx the SEO people suggest these days.

brandonbloom··on Microsoft REST API Guidelines
Big +1 to killing offset in favor of order-by and an "after" or "before" criteria.

However, -1 to the idea of sticking any important "metadata" in headers. For one, it's dramatically easier to interact with response bodies than headers at the terminal or with simple programming libraries and tools. Having only one way of representing data requires fewer special cases. JSON is far superior to key/value pairs in terms of ability to represent structure. Lastly, if you ever decide to use a different "transport" protocol other than HTTP, you'll be glad you are already using a common representation without a side channel.

brandonbloom··on Why Land and Homes Actually Tend to Be Disappointing Investments
You're not accounting for down payment money.
brandonbloom··on Introducing React's Error Code System
How much does does this save? Is it really worth the complexity?
brandonbloom··on Why I'll never abbreviate a variable as long as I live
Even with a 200 character variable name, the chance of collision is 100% if it was auto-completed or copy-pasted.
brandonbloom··on To Compete Better, States Are Trying to Curb Noncompete Pacts
I absolutely love the idea. Kinda like a https://tldrlegal.com/ for employment agreements. Somebody should build that.
brandonbloom··on My Increasing Frustration with Clojure
You'll only be shamed (by me) if you go write a long blog post complaining about it. I don't represent the entire community. Otherwise, you'll be politely corrected and have the tradeoffs explained to you in IRC or Slack. My apologies if I've given you any other impression.
brandonbloom··on My Increasing Frustration with Clojure
My apologies. The community is actually quite welcoming to beginners.

For context, these arguments made by the original poster have been around for _years_ in the Clojure community and, frankly, those of us who have also been around for years are tired of hearing the same old complaints. It's particularly annoying because: the core team has made multiple announcements in past days/weeks about improvements to exactly what he's complaining about!

brandonbloom··on My Increasing Frustration with Clojure
> The C standard for example clearly shows the areas where there is an undefined behaviour and when you can expect the "garbage in, garbage out" behaviour. Is Clojure doing the same?

Yes. In fact, this is partly what clojure.spec is about; which the original author calls out as being wrong to prioritize for some unknown reason.

brandonbloom··on My Increasing Frustration with Clojure
> Telling people that they're not doing a good job when you don't even know them only pisses people off, and eliminates any chance that they'll agree with you on principle.

Funny, that's exactly what the original poster did to the Clojure core team.

> Each time I summarized

You call it summarizing, I call it mischaracterizing. I stand by the position that if the original poster thinks that clojure.set is bugged: they don't know what they are talking about. That doesn't mean they suck at their job, that means they haven't actually stopped to think about the particularities of those functions.

brandonbloom··on My Increasing Frustration with Clojure
> why does efficient set union of two collections require one of the two collections to support fast membership tests

Sorry, I misspoke / used bad shorthand. Union should have efficient set addition for the larger argument and set _intersection_ requires efficient membership tests.

brandonbloom··on My Increasing Frustration with Clojure
> Is it really so wrong ...

No, that would be _wonderful_. Unfortunately, "easy" is only one dimension along which we must make tradeoffs. Clojure has chosen one point in the design space for input validation vs performance. You're free to have a different preference.

brandonbloom··on My Increasing Frustration with Clojure
You're ignoring the fact that I don't believe clojure.set to be buggy.
brandonbloom··on My Increasing Frustration with Clojure
No, I'm saying you should stop and think about what you're doing.
brandonbloom··on My Increasing Frustration with Clojure

    cljs.user=> (source clojure.set/union)
    (defn union
      "Return a set that is the union of the input sets"
      ([] #{})
      ([s1] s1)
      ([s1 s2]
         (if (< (count s1) (count s2))
           (reduce conj s2 s1)
           (reduce conj s1 s2)))
      ([s1 s2 & sets]
         (let [bubbled-sets (bubble-max-key count (conj sets s2 s1))]
           (reduce into (first bubbled-sets) (rest bubbled-sets)))))
    nil
    cljs.user=> (source clojure.set/intersection)
    (defn intersection
      "Return a set that is the intersection of the input sets"
      ([s1] s1)
      ([s1 s2]
         (if (< (count s2) (count s1))
           (recur s2 s1)
           (reduce (fn [result item]
                       (if (contains? s2 item)
             result
                         (disj result item)))
             s1 s1)))
      ([s1 s2 & sets] 
         (let [bubbled-sets (bubble-max-key #(- (count %)) (conj sets s2 s1))]
           (reduce intersection (first bubbled-sets) (rest bubbled-sets)))))
    nil
brandonbloom··on My Increasing Frustration with Clojure
If you take the stance of "nothing is free", then the word "free" isn't particularly useful.
brandonbloom··on My Increasing Frustration with Clojure
C absolutely is a language by/for people who know what they are doing. The fact that so many people are using it for so many things where modern safer languages now exist is not a failing of C or its designers...

Regarding misusing the set functions: There is no busy work. Instead of (set/intersect some-set some-list) you just need to do (set/intersect some-set (set some-list)) to explicitly opt in to the speed tradeoff of performing set operations on lists.

> is a bad idea and those that propagate it should feel bad.

I don't feel bad about it at all.

If Clojure hadn't followed the garbage-in/garbage-out strategy, it would have been too slow for production use. If they had added strong types early or Racket-style (read: slow) contracts, then we'd never have had the years of experience that led to the design of spec, which is new take on the problem space.

In the case of the set functions, the right thing _can not_ be inferred automatically without a speed tradeoff.

brandonbloom··on My Increasing Frustration with Clojure
I anticipated this response to the word "free", but I stand by my statement.

Clojure is _free_. If you don't want Cognitect stuff, don't use it. If you don't like how Rich/Cognitect et al are running the project, take your EPL licensed ball and go home. Similarly, in the case of Go: Substitute Rob/Google and BSD-ish license.

Just because these languages serve the interests of their respective maintainers does not make them any less free to you. It may make the community less useful to _you_, but hey, they created these things to be useful to them. There's an implicitly mutually beneficial social contract around contributions and community. If you don't like that contract, don't use the language.

In the very unlikely case that Cognitect or Google puts some company-specific stuff in the language in a way that actively destroys the good will of this social contract, then and only then do you have any right to complain.

brandonbloom··on My Increasing Frustration with Clojure
Clojure is a language for people who know what they are doing by people who know what they are doing.

If you're giving sequences to the set functions, you either (A) don't know what you're doing or (B) have yet to discover that clojure.set is not what you want.

Set union can't be done efficiently on arbitrarily sized sequences. At least one of the two arguments needs to offer fast set membership; ideally the larger one, hence the requirement that all arguments be actual sets. If you have sequences, you need to make an explicit decision to pay the cost of indexing (eg. via set or into functions) or you need custom code for your use case.

Sure, static or dynamic enforcement could help catch silly errors here, but then the author goes and poo poos on "greenfield" development of things like spec, despite the fact that would "fix the bug" exactly as requested by throwing when you gave non-sets to the set functions.

I've followed a lot of the discussion around the supposedly horrible way the Clojure community is run. So far, the absolutely only complaint that I can sympathize with is that communication could be faster, clearer, and softer. Alex Miller has made dramatic strides in improving this, but he's just one man. Cut these guys some slack, they work crazy hard to build and shepherd something awesome for free.

brandonbloom··on JavaScript async/await implemented in V8
1) Yes, you can restructure/destructure variables at each step, but you're just unifying the control flow and data flow by hand. Yet another flavor of human compiler.

2) catch's entire purpose is to be a catch-all for unexpected errors. For expected errors, it's better to have explicit error values. Bluebird.js at least lets you differentiate .catch from .error, where .error handles the explicit error values generated from traditional Node.js callbacks.

brandonbloom··on JavaScript async/await implemented in V8
You can google that quote and find more, but the control flow vs data flow formulation is not widely discussed from what I've seen.
brandonbloom··on JavaScript async/await implemented in V8
Allow me to make both a theoretical and practical argument.

It's been said that "callbacks are imperative; promises are functional". It's true. Furthermore, callbacks structure control flow and promises structure data flow. Instruction scheduling is an explicit sequence with callbacks (well, assuming the API calls you back precisely once), but scheduling is an implicit topological sort of the directed acyclic dependency graph of promises.

Sometimes, when it comes to side effects, implicit scheduling is less than ideal. You need specific things to happen in a specific order. The solution is to introduce data dependencies to force a particular schedule. This is precisely what is done by monads in Haskell. However, unlike Haskell, JavaScript doesn't have "do" syntax, so there's no convenient notation for a nested chain of bindings.

The result of not having monadic binding syntax is that you wind up with some funky nested chain of getY(x).then(y => y.then(z => z.then(.... OR you have to declare variables up top, flatten your then blocks in to a promise chain, and often ignore intermediate values:

    let y, z;
    getY(x)
    .then(returnedY => { y = returnedY; return zPromise(); )
    .then(returnedZ => { z = returnedZ; return ......; }
    .then(......another side effect.....)
    .then(_ => f(y, z))
async/await neatly eliminates this problem by reusing the traditional coupling of data flow dependencies with first-order control flow dependencies.

Practically:

    let y = await getY(x);
    let z = await getZ(y);
    ......another side effect....
    return f(y, z)
brandonbloom··on Amazon open-sources Ion – a binary and text interchangable, typed JSON-superset
EDN supports dates, etc, too.

However, it doesn't support blobs. I'm conflicted about this point. On one hand, small blobs can occasionally be useful to send within a larger payload. On the other hand, small blobs almost always become large blobs, and so I'd rather plan for out-of-band (preferably even content addressable) representations of blobs.

brandonbloom··on Hjson, the Human JSON
The notion that comments are neither simple nor really necessary is completely bonkers to me, or anyone else who has implemented a lexer or tried to debug an undocumented config file.
← PreviousPage 6 of 16Next →