It was honestly one of the most productive environments I ever worked in, and I'm somewhat sad nobody else has implemented this.
It was honestly one of the most productive environments I ever worked in, and I'm somewhat sad nobody else has implemented this.
Found hole `_' with type f (Free f b)
and relevant bindings, if applicable: Relevant bindings include
>>= :: Free f a -> (a -> Free f b) -> Free f b
(bound at holes.hs:28:3)
f :: f (Free f a) (bound at holes.hs:29:8)
g :: a -> Free f b (bound at holes.hs:29:14)
In the first argument of `Free', namely `_'
Very useful for working your way out of a situation where the specific incantation to get to the right type isn't obvious.Examples from [0].
It does sound like a good feature though - very few languages have opt-out type checking. This is much better than opt-in IMO.
$ cat foo.hs
something = to be done
x = x + 1
wat = x "¯\\_(ツ)_/¯"
main = print "hi"
$ ghc --make -O foo -fdefer-type-errors && echo sucesfuly compoiled && ./foo
[1 of 1] Compiling Main ( foo.hs, foo.o )
foo.hs:2:13: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: to :: t1 -> t2 -> t
|
2 | something = to be done
| ^^
foo.hs:2:16: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: be
|
2 | something = to be done
| ^^
foo.hs:2:19: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: done
|
2 | something = to be done
| ^^^^
Linking foo ...
sucesfuly compoiled
"hi"
$Typed holes (but not the defer- option) have been enabled by default for some time now. They're an immediate go-to when scratching my head over types. I prefer them to the type error output, not only because they give better suggestions, but also because they can be named (_a, _conversionFunction, etc).
I'm asking as I prefer strict compilers that force me to handle all cases.
In an ideal world, the codebase would be modular and testable and all those good things but I work in a large enterprise dev team and some of the codebase is many (many) years old and it's no longer feasible to refactor it into anything like what would be needed to allow the code to be modularized in such a way that would obviate the necessity to do the above.
func TestWhatever(t *testing.T) {
// ...lots of code
_, _, _, _, _, _, _ = resp3, resp4, fooBefore, subFoo, bar2, barNew, zap2
}
Like, I get it, it's a good feature, it caught quite a lot of typos in my code but can I please get an option to turn this checking off e.g. in unit tests? I just want to yank some APIs, look at their behaviour, and tinker a bit with the data.The go devs decided against this since they didn't want to build a highly optimizing (read: slow) compiler, but that is missing the point of developer ergonomics.
Most people nowadays ban building with warnings in CI and allow them during local development. But “CI” was barely a thing when go was developed so they just banned them completely. And now they are probably too stubborn to change.
Q. Why can’t I have feature X?
A. We thought of that already, and your opinion is wrong.
Q. But basically every other language in existence supports this. And it makes development easier. We would really, really like it. Please?
A. Apparently you don’t get it. Here’s a pointer to a 15 year-old post on a mailing list where the first time someone asked for this, we said no. Your opinion is wrong.
Sounds like we agree!
https://gist.github.com/umanwizard/9793393083a42db933579fe21...
func TestWhatever(t *testing.T) {
var resp3, resp4, fooBefore, subFoo, bar2, barNew, zap2 theirType
// ...lots of code
}
Alternatively, use '_' where they are being defined: // instead of
resp2, err := doit()
// use
_, err := doit()
If, and given this context it's likely, you're checking these errors with asserts, then either change the name of the error variable, predeclare the err name (`var err error`), or split it into multiple tests instead of one giant spaghetti super test.That said, in a code review, at a minimum, I would probably ask that these variables be checked for nil/default which would completely eliminate this problem.
foo, fooErr := doit()
require.NotNil(foo)
require.NoError(fooErr)
_, _ = foo, fooErr // alternative if you don't want the asserts for some reason, remember to come back later and delete though
// ...repl churn code...
Using the stretchr/testify/require package. This code defines both variables, gives the error a unique name in the scope, and then references the names in two asserts. You won't have to deal with unreferenced name errors in the "repl churn", so you can comment/uncomment code as you go.The really neat thing was that the Ecliose Java compiler is built specifically to support the IDE, so all the the warning and error annotations in the editor come from the actual compiler even while you are typing. There is no separate parser and linter just for the editor. I believe that the ability to translate broken source files on a best effort basis is actually an offshoot from that functionality.
When it worked, it was really, really good, agree. My experience was that it usually didn’t though, swap branches a few times and the caches would be broken, time for “invalidate caches and restart”. Multiple times per week, each time it’d take an hour to re-index.. that was a lot of time we got back again when we switched to IntelliJ
You could literally start the skeleton of a webserver and gradually add functionality to it without recompiling and it would mostly "just work". Certain changes would require the app to be restarted.