`conform` also has an inverse function `unform`. They are useful for converting between linear (like a list) and nested (like a map) shapes of data. You can imagine heaving a compressed data in a list that you save into a file or send via network. Types of values specified by their position in the list. When you want to work with it you conform it into a nested (map) view using a spec and when you done you "save" it back into linear view via unform. You can implement "(reform ) " - takes and returns lists but applies passed function to the collection as if it was in the nested form instead of a list. Kinda cool :D
Cool video as always! It is important to point out that the test check thingy uses argument specs to generate test values and passes them to the function, then it checks if every return value matches the function's return spec. Another cool feature is that test check can shrink error - when it finds a mismatching value, it will try to reproduce a minimal failing case.
Hey! I just want to say that the way you actually showed a common error at 8:10, diagnosed it, and then fixed it was really helpful! A lot of educational programming content just shows the happy path, but as a beginner I mess up a lot. This makes me think that a video where you explain common error messages (or just tacking that on to other subject specific videos) would also be helpful!
Thanks for the comment man! :) its super tricky to do a video based on that because different errors pop up doing different things. If you have a particular error that you want help with i can try?
@@onthecodeagain Hmm I'll share confusing error messages as they come, but I tried this code: (ns emotion-modeling-lfb.core (:require [clojure.spec.alpha :as s] [clojure.spec.test.alpha :as stest] [clojure.spec.gen.alpha :as sgen])) (s/def ::between-0-100 (s/and int? #(> 101 % 0))) (s/exercise ::between-0-100) And got this error message on the exercise function: Execution error (FileNotFoundException) at emotion-modeling-lfb.core/eval1617 (form-init13010486330272312439.clj:1). Could not locate clojure/test/check/generators__init.class, clojure/test/check/generators.clj or clojure/test/check/generators.cljc on classpath. And `[org.clojure/test.check "1.1.0"]` is in my Leiningen project dependencies
Great video with nice clear explanations. In a real project would you place the spec along side each function, or create a new 'test' namespace with all the specs and tests?
Quick note on the end of the video: you could also use preconditions and postconditions to check the input and output values of a function. E.g. {:pre [(cond1) (cond2]}. They do however, throw Errors in case of failure, which may not be what you want.
Hello, I am using intellij instead of vs code and at 14:37 I don't see (in my ide) a way to reload the terminal (I use the terminal instead of calva, I just open the terminal and then type the clojure command), how can I make the terminal reloads? and btw, very good tutorial
With specs you can create a type (contract) like "map function should return collection with the same number of elements as the input argument that also a collection" or "sort function should return sorted collection" Good luck doing it with a type system...
Spec is a step above types :) it allows you to implement design-by-contract in your project (en.wikipedia.org/wiki/Design_by_contract) which can garuntee that your functions and their behaviour work exactly how they should.
@@onthecodeagain Not specificaly "dark mode" but "darker mode" :) . BTW why not sync your videos to lbry / odysee would be happy to send you some tips there.
@@YisraelDovL I didnt know about lbry / odysee before these comments :p Just signed up, apparently the account sync can take up to a week... when its finished I'll post a link to the channel here. Appreciate the help!
great video again, keep it up! I didn't quite understand the generated tests part... Whats the use case of that function you created for the :ret? If it generates 1000 possible values how can we even have conditions here? They are dedtined to fail then, no? What would be a use case/ :ret fn in the real world? Or in anpractical example? Once again the question might be stupid, have not yet coded more than the firdt chapter of the guide in clojure page, but I am in love with this language. greetings
Hey hows the learning going? A practical example of ret would be to ensure that the type that was returned is valid or if its within a certain number range or matches any constraints you can think of for what your return value should be
`conform` also has an inverse function `unform`. They are useful for converting between linear (like a list) and nested (like a map) shapes of data. You can imagine heaving a compressed data in a list that you save into a file or send via network. Types of values specified by their position in the list. When you want to work with it you conform it into a nested (map) view using a spec and when you done you "save" it back into linear view via unform. You can implement "(reform ) " - takes and returns lists but applies passed function to the collection as if it was in the nested form instead of a list. Kinda cool :D
You might well be the superpower that the Clojure community needs, great video!
I appreciate that!
Thank you for sharing your experience, I am learning clojure and your videos help a lot!
Cool video as always! It is important to point out that the test check thingy uses argument specs to generate test values and passes them to the function, then it checks if every return value matches the function's return spec. Another cool feature is that test check can shrink error - when it finds a mismatching value, it will try to reproduce a minimal failing case.
Thanks a lot dude! Yeah I realised I may have went a bit quick over the testing part... I have a generative testing video lined up also.
Hey! I just want to say that the way you actually showed a common error at 8:10, diagnosed it, and then fixed it was really helpful! A lot of educational programming content just shows the happy path, but as a beginner I mess up a lot.
This makes me think that a video where you explain common error messages (or just tacking that on to other subject specific videos) would also be helpful!
Thanks for the comment man! :) its super tricky to do a video based on that because different errors pop up doing different things. If you have a particular error that you want help with i can try?
@@onthecodeagain Hmm I'll share confusing error messages as they come, but I tried this code:
(ns emotion-modeling-lfb.core
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]
[clojure.spec.gen.alpha :as sgen]))
(s/def ::between-0-100
(s/and int?
#(> 101 % 0)))
(s/exercise ::between-0-100)
And got this error message on the exercise function:
Execution error (FileNotFoundException) at emotion-modeling-lfb.core/eval1617 (form-init13010486330272312439.clj:1).
Could not locate clojure/test/check/generators__init.class, clojure/test/check/generators.clj or clojure/test/check/generators.cljc on classpath.
And `[org.clojure/test.check "1.1.0"]` is in my Leiningen project dependencies
Update: Just tried restarting the REPL and it worked. I was just reloading the file into the REPL, which I now know isn’t enough.
Thanks for sharing! 🧙♂️
Spectacular video.
Thanks a lot! :D (I wish I thought of that in my video...)
Thanks man! I was literally just starting using this in my clojure API.
Thats awesome :) I hope you found this useful!
Great video with nice clear explanations.
In a real project would you place the spec along side each function, or create a new 'test' namespace with all the specs and tests?
Awesome thanks! :) I would say it depends on how you organize your project. Im fond of separate namespaces and files though
great stuff as always
Thanks a lot man! :)
There is also ::foo/bar qualified key form. It is useful if you have to deal with a lot of qualified keys from different namespaces.
foo is an alias for a namespace.
Yeah, a video on ns (like you suggested) would be a great place to include this!
on the code again
❤🔥
Quick note on the end of the video: you could also use preconditions and postconditions to check the input and output values of a function. E.g. {:pre [(cond1) (cond2]}. They do however, throw Errors in case of failure, which may not be what you want.
Think ill do a video on function meta data at some point and show that also
Btw defn-spec (from orchestra) also checks return specs by default.
didnt know about that at all!
Hello, I am using intellij instead of vs code and at 14:37 I don't see (in my ide) a way to reload the terminal (I use the terminal instead of calva, I just open the terminal and then type the clojure command), how can I make the terminal reloads? and btw, very good tutorial
great video!
please make more live coding videos like this
posting a new vid on Monday :) I haven't been active this last month because of covid :/
You can get a sample values satisfying a spec with `s/exercise`
Thats handy!
What is your view on spec as an ad hoc type system?
With specs you can create a type (contract) like "map function should return collection with the same number of elements as the input argument that also a collection" or "sort function should return sorted collection" Good luck doing it with a type system...
Spec is a step above types :) it allows you to implement design-by-contract in your project (en.wikipedia.org/wiki/Design_by_contract) which can garuntee that your functions and their behaviour work exactly how they should.
Really good video. :)
Thanks!
OY! Am I the only one that is being blinded by the light theme ? I enjoy the videos, but I wish there was a filter to turn down the brightness.
Haha was wondering when I'd get a light theme comment. I'll use dark mode in future 👌🏽
@@onthecodeagain Not specificaly "dark mode" but "darker mode" :) . BTW why not sync your videos to lbry / odysee would be happy to send you some tips there.
@@YisraelDovL yeah please send me tips!
@@onthecodeagain Can't find your lbry channel , post a link to there.
@@YisraelDovL I didnt know about lbry / odysee before these comments :p Just signed up, apparently the account sync can take up to a week... when its finished I'll post a link to the channel here. Appreciate the help!
great video again, keep it up!
I didn't quite understand the generated tests part...
Whats the use case of that function you created for the :ret?
If it generates 1000 possible values how can we even have conditions here? They are dedtined to fail then, no?
What would be a use case/ :ret fn in the real world? Or in anpractical example?
Once again the question might be stupid, have not yet coded more than the firdt chapter of the guide in clojure page, but I am in love with this language.
greetings
Hey hows the learning going?
A practical example of ret would be to ensure that the type that was returned is valid or if its within a certain number range or matches any constraints you can think of for what your return value should be