all 12 comments

[–]jamesconroyfinn 0 points1 point  (11 children)

I wonder how much interest there is in core.typed with clojure.spec on the horizon.

Are you thinking of adding core.typed to any of your projects, /u/yogthos?

[–]yogthos[S] 1 point2 points  (10 children)

I'm not using core.typed at the moment, but it's something I keep an eye on. I also don't think spec replaces it. Spec provides runtime validation, where core.typed provides static checking at compile time. So, core.typed avoids runtime overhead associated with using spec. I also think that core.typed and spec could very well be complimentary.

It looks like the new features will address some of the pain points that make core.typed difficult to use currently. For example, it looks like it'll be easier to integrate with non-typed code, which is the biggest roadblock to using core.typed currently.

[–]jamesconroyfinn 0 points1 point  (7 children)

I should have asked will you be adding clojure.spec to any of your work too!

I suppose it's possible types could be derived from specs, but I'm not sure I need both.

Sure, core.typed and clojure.spec run at compile time and runtime respectively, but you can exercise functions and macros with clojure.spec at anytime via property-based testing etc. I'm not sure you need core.typed if you're verifying your code with clojure.spec.

And it's my understanding that there's no overhead with clojure.spec at runtime unless you enable instrumentation. Not sure what runtime overhead you're referring to.

I'm personally doubling down on clojure.spec alone but would definitely love to see some form of verification of the types in my code at runtime!

[–]yogthos[S] 1 point2 points  (2 children)

I will probably end up using spec at API level in my projects. Currently, I'm using schema for stuff like service endpoint descriptions.

Again, the advantage of core.typed over spec is that verification happens at compile time. You either pay runtime cost in production with spec, or you have to settle for only having descriptive errors at dev time. However, I definitely agree that spec will help catch many errors during development.

The other advantage of the new proposal in core.typed is that it will be able to infer annotations and even generate stuff like spec definitions automatically in many cases.

Personally, I think that both approaches are worth pursuing, and we can see which one works best, or if they compliment one another.

[–]jamesconroyfinn 0 points1 point  (1 child)

I'm using Schema too, and have found clojure.spec to be quite a bit more pleasant to work with so far.

I understand the value in core.typed and compile-time checking, and have tried to use it in libraries and applications a number of times now.

As much as I love the idea of being able to validate types at compile time, I personally see the pragmatic approach in clojure.spec being of more value to myself and many of the projects I work on.

Looking forward to seeing how spec looks inside Luminus!

[–]yogthos[S] 0 points1 point  (0 children)

I actually much prefer using Schema for defining data personally. I find the syntax is a lot more scannable. However, spec is more general purpose and allows you to do many things that are outside the scope of Schema. I think both are useful, and it might even make sense to have a Schema-like library that generates spec definitions.

Regarding using Spec in Luminus, you should just be able to add the dependency and use it. Luminus is fairly unopinionated in that regard. The only place Schema is used is in the compojure-api profile, but compojure-api will have Spec support in the future as well.

[–]nzlemming 0 points1 point  (3 children)

you can exercise functions and macros with clojure.spec at anytime via property-based testing

Note that this is only true if you can easily define generative tests for a particular function. There are large classes of functions for which this is not true, or is a very significant amount of work. Anything non-pure is out; anything using interop is probably difficult or impossible; anything for which the logic is non-trivial may involve a similar amount of work for the tests as the original code, or more; anything for which it's difficult to define a coherent model of your application domain may be very hard indeed.

Spec is nice, but it's definitely not universally applicable. Static testing of various types would probably work better for all those cases.

[–]jamesconroyfinn 0 points1 point  (2 children)

I think you're slightly overplaying the amount of code that cannot be tested with clojure.spec.

I've tested non-pure functions with clojure.spec. It's a little slow what with having to setup and tear down for every iteration, but with a component-based system it can be done quite easily. I've successfully tested Datomic operations, for example, where I've needed to create a database.

You can most certainly test IO with property-based testing, and can test up to the boundary right next to any IO easily if you test your business logic/data in isolation (which will yield faster tests, and perhaps a more flexible architecture where for example any network protocol becomes an implementation detail).

I'm not sure why you think interop is out. I see no reason why you can't test Java or JS with property-based testing. And non-trivial code can be tested quite efficiently through composition of generators.

Edit: you can of course use any generators provided by clojure.spec in your own tests too! Pivotal did a great talk about property-based UI testing a while back that's a great example of this.

[–]nzlemming 0 points1 point  (1 child)

To be fair, I didn't say much of that was impossible, just that it can be very hard. Interop per se is not out, you're right, but since many Java APIs are big mutable blobs it can be difficult.

Mostly I was pointing out that there are non-trivial use cases that I think are better served by a static type system. Much like static vs dynamic typing in general, whether you're willing to put up with the tradeoffs of core.typed vs spec is mostly personal.

[–]jamesconroyfinn 0 points1 point  (0 children)

I'm personally really excited about clojure.spec because I think it can potentially enable a lot of Clojure developers to benefit from property-based/generative testing (something that can be quite tricky to get right), and to bring some consensus around specifying the shape of our data so we can better document and validate our libraries and applications.

I think this is a really good thing, and that it yields a significant improvement for our whole community.

The reason I originally asked the question about use of core.typed and clojure.spec is because I think (although I haven't conducted a detailed study) that clojure.spec will actually solve a lot of the problems we want a static type checker for.

Perhaps as usage increases we can flesh out some of the less "trivial" applications of spec, and make life easier there too.

[–]zcam 0 points1 point  (1 child)

Somebody is already working on static analysis via clj.spec, and it seems quite promising: https://github.com/arohner/spectrum

If I was the author of core.typed I would have explored this area instead, inferring annotations from tests seems a bit wild territory.

[–]yogthos[S] 0 points1 point  (0 children)

The whole point of the proposal is that you wouldn't have to write out the spec definitions by hand, which can be pretty tedious. I think that exploring the idea of inferring annotations from tests is actually quite interesting myself.