14,908 karma · joined May 29, 2012
In a sense, but it's not the program we wanted to write, and types can be a useful way of moving that kind of information around within a program during development.
> TypeScript is not designed to stop you from using string prototype methods on... strings!
No, but it is designed to let me design my types to stop myself from accidentally using string prototype methods on data to which they don't actually apply, even when that data happens to be represented as... strings.
My point - inasmuch as there was a serious one - wasn't that we shouldn't raise our standards but that the framing isn't particularly helpful in determining whether we should (while rhetorically sounding like it is).
Isn't everyone ok with that by the definition of "passable"?
Yeah, I was going to say, it's worth asking.
I find this take surprising. Leaving AI aside entirely, debugging my first draft seems very different than debugging your first draft.
... or, failing that, a different good C-suite might want to hire away from a less good C-suite.
I just find that "always squash the entire branch" is a common reaction to "history is messy" and I wanted to surface that (per my understanding) it doesn't actually improve the situation (vis-a-vis bisect in particular, assuming you're passing the correct arguments for your situation) over merging (no-ff, I neglected to specify...) branches where some of the commits do not build.
It seems to me that, with respect to bisecting, a merge workflow with git bisect --first-parent is equivalent to a squash workflow with a bare git bisect. Am I missing some way in which that's not the case?
The bigger deal is that things are never shared simply for being in the reflog - which is probably correct for its intended use but doesn't really fit what's asked for up thread.
And agricultural co-ops are neither.
Collective nouns.
My experience is the opposite - a sizeable chain of ifs has more that can go wrong precisely because it is more flexible. If I'm looking at a switch, I immediately know, for instance, that none of the tests modifies anything.
Meanwhile, while a missing break can be a brutal error in a language that allows it, it's usually trivial to set up linting to require either an explicit break or a comment indicating fallthrough.
I was a STEM major, did well at a reasonable school, and the only time I felt like I had way the hell more homework than I could get through was at a community college when I signed up for a Literature course and a Political Science course the same summer.
Whether 4B is doable depends on how much work you're doing for each of those states, but yes, "4B" alone certainly doesn't rule it out. There's also a question of whether it goes with your most frequently run tests or is something that's only run occasionally.
> However a lot of algorithms can have more than 32 bits of states and so quickly get beyond what is doable.
I'm pretty confident we're all in agreement there.
The whole program? Yes.
For testing individual components, there's no need to assume. The answer is very likely either clearly yes (the input is a handful of booleans) or clearly no (the input is several integers or even unbounded) and for those cases where it's not immediately clear (one i16? Three u8s?) it's probably still not hard to think through for your particular case in your particular context.
As you say, though, exhaustive testing is sometimes possible.
I think you're talking here about abstracting over the underlying monad, with a different implementation for testing than for production. That can work well[1], but it's not what I was talking about.
With my Writer (nb: io., not Control.Monad.) example, how does Haskell make it harder? I'm not talking about replacing the underlying monad, but to define an interface in terms of that underlying monad.
Fleshing it out, something like:
main :: IO ()
main = flip runReaderT () $ do
-- with Handle
writeStrings stdout
-- with IOVar
var <- liftIO $ newMVar ([] :: [ByteString])
writeStrings var
liftIO $ print =<< takeMVar var
writeStrings :: Writer w => w -> ReaderT r IO ()
writeStrings w = do
write w $ pack "oh hi\n"
write w $ pack "uh\n"
write w $ pack "bye then\n"
class Writer w where
write :: w -> ByteString -> ReaderT r IO ()
instance Writer Handle where
write w bs = liftIO $ hPut w bs
instance Writer (MVar [ByteString]) where
write w bs = liftIO $ modifyMVar_ w $ \ bss -> pure (bs:bss)
[1] A digression: Taking that approach, I think it's generally most comfortable to use a unique base type for each test (or natural clusters of them) and implement just the interfaces you need with an eye to the particular tests. The biggest problem I've seen is a tendency to push too much into that environment and thereby make too much implicit, which can make it confusing to distinguish and lead to things like the confused deputy problem.Okay, but is it an okay topic for a history podcast like the one sobellian was apparently listening to?