HN user

kvb

967 karma

I'm a Microsoft employee, but I speak only for myself.

Posts1
Comments376
View on HN

I think it is pretty hard to compute the cost, because what's the counterfactual? Even if you don't force a shutdown people may still opt to isolate themselves and businesses may opt to close, and the degree to which they do so is probably dependent on the dynamics of the pandemic, so you're going to be pretty sensitive to modeling errors.

So if you know of 10 different events which may occur with probability 10% each, you would prepare for exactly one of them?

I think it's clear that there are some events that may be rare but which are cheaper to plan ahead for than to deal with after the fact, and vice versa (e.g. for many people self insuring against minor losses like appliance failures makes sense).

But we can all aspire to be a >1 developer, even if we're not one currently. I don't necessarily think that contentment with being below average is universally bad (maybe it's perfectly rational given one's preferences for leisure vs. work, for example), but I'd hope that most <1 developers are juniors who hope to improve over time.

But writing code is only a small part of a software engineer's job (at least that's true everywhere I've worked), so selecting people who have opted to dedicate their lives to only that portion might be a worse idea than hiring better-rounded candidates, when it comes to building real software systems that need to be liked by users.

I would certainly dispute that programming time is necessarily slowed down. Ironically, I find myself thinking much harder about types in a dynamic language, precisely because there's no compiler there to do the rote work for me. Lately I've been using pandas dataframes quite a bit, and the number of hours I've wasted due to problems with types is mindboggling.

Non-polymorphic functions of the type `a->a` trivially satisfy it, of course. Also, I think polymorphic functions are the most interesting case where you can't use twice as desired in an ML-like language, so it's too bad that despite the fancier type they don't work too well in MLsub. Here's another example that fails when I'd hope for it to succeed:

  let one = twice (fun o -> o.x) { x = { x = 1 } }

Though note that an even better type would probably be

    twice : forall a,b,c. ((a->b)&(b->c)) -> a -> c
(e.g. in MLSub, the type for
    twice (fun x -> x::[]) 1
is the unsatisfying
    (rec a = (a list | int) list)
rather than the expected
    (int list) list

)

I like the way Scott Alexander frames the effect size. This is from the conclusion the blog post you link:

  An important point I want to start the conclusion section
  with: no matter what else you believe, antidepressants are 
  not literally ineffective. Even the most critical study – 
  Kirsch 2008 – finds antidepressants to outperform placebo 
  with p < .0001 significance. An equally important point: 
  everyone except those two Scandinavian guys with the long 
  names agree that, if you count the placebo effect, 
  antidepressants are extremely impressive. The difference 
  between a person who gets an antidepressant and a person 
  who gets no treatment at all is like night and day. The 
  debate takes place within the bounds set by those two 
  statements. Antidepressants give a very modest benefit 
  over placebo. Whether this benefit is so modest as to not 
  be worth talking about depends on what level of benefits 
  you consider so modest as to not be worth talking about. 
  If you are as depressed as the average person who 
  participates in studies of antidepressants, you can expect 
  an antidepressant to have an over-placebo-benefit with an 
  effect size of 0.3 to 0.5. That's the equivalent of a diet 
  pill that gives you an average weight loss of 9 to 14 
  pounds, or a growth hormone that makes you grow on average 
  0.8 to 1.4 inches.
Note that this is the over-placebo benefit, and placebos already have a large benefit in most depression studies.

Your particular example doesn't seem especially object oriented (e.g. it looks like a simple data type with a "smart constructor", which is a common pattern in, say, Haskell, too). But in any case F# supports both discriminated unions as well as normal OO design, while C# supports only the latter, so in that subset of cases that are better modeled by DUs F# will be strictly better, and in the rest of the cases it won't be worse.

But someone else could create a subclass breaking the invariants. It's possible to avoid this by making the abstract class's constructor private and nesting the two subclasses inside of the abstract class, but this is not idiomatic. If you have to work that hard then most people won't bother, while in F# it's very natural to create such a design.

Idiomatic F# code also uses Option types. However, all .NET reference types have null as a possible value. While most F# types don't have null as a "normal" value, there's nothing to prevent null instances of these types from being created "abnormally" at the .NET runtime layer (e.g. values of F# types created in other .NET languages like C# that don't respect F#'s metadata annotations, or created via F# operators like Unchecked.defaultof<_> that implicitly use the .NET runtime's default value of null for reference types).

In practice this is rarely a problem, but the article is highlighting what you need to do when you want to (efficiently) check for these boundary cases.