Devenv.sh: Fast and reproducible developer environments using Nix
devenv.sh382 pointsby frankpf158 comments
type Email = distinct string
Now Email is a type that is incompatible with string, even though its runtime representation is a string (i.e. no additional overhead). To convert a string to an Email, you can call Email("a"). In real-world code, you would call that constructor only in a few "safe" functions: # I'm raising an exception, but you could use an option or a result type
proc validateEmail(str: string): Email =
if email.contains("@"):
return Email(str)
raise newException(InvalidEmail, "not valid")
Then, in your client code you can have: proc createUser(email: Email, password: Password) =
...
And the type system guarantees that you only call createUser with "Email"s, not plain strings. Of course, you have to be dilligent not to use the Email constructor directly and instead use the validateEmail function to create "Email"s. proc safeDivide(a: int, b: int): float {.requires b > 0.} =
a / b
and DrNim will check at compile-time that all code paths lead to `b` being greater than 0, e.g.: var x = stdin.readLine.parseInt
safeDivide(1, x) # DrNim will error at compile-time
var y = stdin.readLine.parseInt
if y > 20:
# no error since DrNim (using Z3) can
# prove that y is always greater than 0 here
safeDivide(1, y)
[1]: https://nim-lang.org/docs/drnim.html require('npm/validatePackageVersions') # or import 'npm/...' in es6
in their top level code. A
=> depends on B @ 1.0
=> depends on C, and C can depend on B @ 2.0
Regarding your second point, I haven't ever seen that happen in practice and IIUC it's mostly a property of the the fact that `require 'bundler/setup'` checks your dependency versions, and you could implement something similar for JS (e.g. traverse node_modules directories recursively checking if the versions declared in the package.json of dependencies match the ones in your root lockfile). (defn greet [firstname lastname]
(def fullname (string firstname " " lastname))
(string "Hello, " fullname))
In other lisps, you'd have the last expression nested inside a `let` block: (defn greet [firstname lastname]
(let [fullname (string firstname " " lastname)]
(string "Hello, " fullname)))
which makes the code hard to read and edit IMO. Languages like Haskell and OCaml suffer from a similar problem too. const ContactInfo = t.type({
address_1: t.string,
...
})
type ContactInfo = t.TypeOf<typeof ContactInfo>
You can validate objects with `ContactInfo.decode(someObject)` knex.insert({ bar: 'bar', baz: 'baz' }).into('foo')