@artemyarulin has joined the channel
Hello, just started to play a bit with spec. Is there any way to make it shorter? Can I somehow embed first-name inside person without separate def?
(s/def ::first-name string?)
(s/def ::last-name string?)
(s/def ::person (s/keys :req [::first-name ::last-name]))
@artemyarulin I don't think there is
hm, ok. It kinda forces me to design everything bottom to the top
I think that's on purpose
OK, thanks
@manishkumarmdb has joined the channel
(s/conform (s/cat :pre (s/& (s/+ #{1 2 3})
(fn [r]
(if (= r [1 2 3])
r
::s/invalid)))
:keyword #{:a})
[1 2 3 :a])
=> {:pre [1 2 3], :keyword :a}For the :pre match I want to match the sequence 1 2 3 in that order as the start of a larger sequence. Is there an easier way to write the spec for the :pre part? I tried stuff like #{[1 2 3]}
@artemyarulin has left the channel
(s/cat :1 #{1} :2 #{2} :3 #{3})
Or similar with s/tuple
But s/tuple can't be used within a regex, right?
Right
I went with:
(defmacro match-seq [c]
(let [ks (vec (mapv keyword (repeatedly (count c) gensym)))
cat-kvs (mapcat vector ks (map hash-set c))]
`(s/with-gen
(s/&
(s/cat ~@cat-kvs)
(s/conformer
(juxt ~@ks)
(fn [out#]
(zipmap ~ks out#))))
(fn []
(s/gen #{~c})))))
(s/conform (s/cat :pre (match-seq [1 2 3])
:keyword #{:a})
[1 2 3 :a])
;=> {:pre [1 2 3], :keyword :a}
just remembered an old happening from the .net world that I thought the folks here may be interested in: https://blogs.msdn.microsoft.com/kathykam/2007/03/29/bye-bye-system-timezone2-hello-system-timezoneinfo/
in short, System.TimeZone was broken in a bunch of ways, so they made System.TimeZone2, but people freaked out about that name, so they caved and called it TimeZoneInfo.... leading to substantial confusion
> using numeric modifier is not scalable in the long term
eventually the numbers just get too big
mathematicians tell us that there is no limit to how big numbers can get
I wonder what the smallest number which isn't representable with the amount of information present in the universe is.
knowing that number would change the amount of information in the world, hence changing that number
Well, I obviously couldn't know it.
I remember watching a ted talk on this, it's interesting. but yeah, what's to stop me saying "the biggest number the universe can represent, times two"
Right, that's a representation.
we could just redefine 1 to be "the biggest number the universe can represent" š
bfabry: the trick is not to abstract over numbers, but to abstract over the operations which generate those numbers
use BB(11111), as scott aaronson suggests
@bfabry If I could find the number by an algorithm, the algorithm would have to require more information to represent than present in the universe to represent.
BB(n) exposes an ambiguity in the question, I suppose -- if a number is platonically well-defined but can't be computed, does that count?
Interesting
I just got to that part
the fun part is I don't even know what I mean by "platonically well-defined"; it's just an emotion
as fun as i find numbers, i was hoping somebody had some insights in to the hardest problem in computer science: the paucity of names š
@bbloom what do you think of the renaming you linked to?
honestly, i liked the name TimeZone2 - it means i donāt need to look at the docs for TimeZone or TimeZoneInfo to know which does what
basically i just ignore TimeZone
i can understand the desire to not have to write TimeZone2 in places
because it's ugly?
you feel like you have to memorize a version number for every class/API you learn to use?
yeah, but specifically itās ugly for an ugly reason: it showcases a mistake
itās not my mistake, but thereās still a human error as an accident of history in my code
now, thatās fine, b/c everything is human errors and accidents of history
my next thought is: ok, so letās use aliases, which is what rich suggested too
but iām not so sure thatās a good solution either
ns aliases in particular? :rename too I guess
yeah, those combined
or even just a simple def
that helps for migration, which is key, but it still kinda sucks b/c of the nature of context
if you and i have a conversation about TimeZone, how do you know which version i mean?
yeah there'll always be a version number at one of the levels
by utilizing rename/alias, you wind up in the same place you started with if you had used semver or whatever (shudder)
function name, ns name, artifact name, ecosystem name...
yeah, well ecosystem name is the easy one
you just invent a brand name and youāre good
every 5-10 years we declare bankruptcy on all this and start a new programming language
like instead of Clojure 2.0 you just fucking call it Twojure or something and you can change whateve ryou want, but at the cost of bifurcating the community
yup lol
and then everybody rushes in to write the first http library
hereās where iād use a /giphy lion king circle of life
I don't think there's any Super Happy approach to this :(
iād settle for a reasonable principal by which i can rationalize my decisions and remain mostly happy that i didnāt LOSE a battle with the laws of nature
alias & rename give us some powerful tools
but i feel like something is missing
one problem iāve run in to a bunch is the impl vs interface namespace problem
spec sorta has this problem in that it has some public macros that itās like ādonāt use me directly please"
and then thereās core.async that has the impl namespaces and then redefs an indirection to export all the functionss
i wonder if there was some way to abstract over aliases and renames that you could more easily address this
not sure what that would look like
but if weāre going to use names as a tool to achieve accretion (and i see no other way, since everything in symbolic reasoning involves names), then i think we need more tools for names
thatās as far as iāve managed to think here </rant>
rich wanted a global mapping from namespaces to maven artifacts
or seemed to at least
this is sort of a different topic
he seemed to be making two points: 1) weāve got bad abstractions: project files, version numbers, etc and 2) accrete, donāt break, use names to do that
if it were up to me, weād abolish artifact ids etc as much as possible - namespaces have much nicer properties
just publish individual namespaces? with versions?
you could probably define some information-preserving algebra of them. ie merge two sets of names, aliases, etc
yeah, i think so
maybe published dates instead of versions, since weāre turning version trees in to sequences
he said the useful thing about artifacts is that they intentionally tie together particular versions of particular namespaces
i mean do they tho? only if you bundle your deps
Hi all. I need spec for map such as: if key - some pred, then value - spec1, else if key - other pred, then value - spec2?
@bbloom I mean if your artifact contains multiple namespaces, which it probably does, they are free to assume things about each other because you know that you'll get exactly the same version of all of them
@gfredericks ah, i understand what youāre saying. yeah, in that sense those are actually tied together and tested together. i think thatās not incompatible with the idea of āeliminatingā artifacts or projects tho⦠you'd just use the context of a project in resolving versions of namespaces, ideally in some content addressable way maybe?
so if i have namespace foo and i require foo.bar, then i have a project that says āhey, iām going to publish namespaces #āfoo.*ā, then when those get published they get tagged with some artifact bundle in some way, but i donāt actually think about that, i think about the version of the nodes in that dependency graph i point to directly
so you resolve internal dependencies within a project using immutable references, like hashes, and then you resolve external dependencies using lamport logic
eg by intersecting date ranges
If backwards compatibility is reliable presumably your date range can be open on the right side and intersections are trivial
right, but of course people make mistakes, so youād probably need two features:
1) right bound to say āi no longer trust this maintainer"
and 2) a black list of bad versions
so your timelines could have right bounds or holes
If intersections are empty then the build tool reports a failure?
yup
and you always select the most recent version from the intersection
then layer on top the standard dependency pinning behavior for prod
i want this. somebody make this.
š
It can be a first-class feature of twojure
alex probably wouldnāt tell us if rich was working on a new tool here š
Twojure has a nice ring to it
It seemed their primary goal was running the minimal set of tests and generative tests for a given change.
here is to hoping they will continue the https://github.com/Datomic/codeq thought
I was able to spec my map with
(s/coll-of (s/or :option1 (s/tuple key-spec-1 val-spec-1) ....)), but path in error messages is not informative: [0 1 0 1]š¤ Iām having trouble supplying generator overrides
(ns scratch
(:require [clojure.spec :as s]
[clojure.spec.gen :as gen]))
(s/def ::id (s/or :tempid int? :uuid uuid?))
(s/def :thing/id ::id)
(s/def :thing/entity (s/keys :req [:thing/id]))
(gen/sample (s/gen :thing/entity
{:thing/id #(gen/int)}))
I would expect that call to gen/sample to give me :thing/entitys with int values for the :thing/id key.
Instead, itās as if I hadnāt supplied the override at all. I get a mix of int and uuids.
::id makes it work
(dunno what the expected behavior is, if that is a bug, etc)
::id in the override map
Yeah, it does. This is a minimized example, but Iād like to keep from overriding all ::ids, and just override thing/entityās
@hiredman thanks, I think your suggestion help me identify my problem. Iām pretty sure itās a bug
(ns scratch
(:require [clojure.spec :as s]
[clojure.spec.gen :as gen]))
(s/def ::number number?)
(s/def ::numeric ::number)
(gen/sample (s/gen ::numeric
{::numeric gen/int}))
I would expect that gen/sample call to only return ints, but it returns ints and floats instead
I think that this means that you canāt override āaliasedā specs, which is a bug?
I hope it's a bug
probably raise a jira, that behaviour is really surprising
boot.user=> (s/def ::numeric ::number)
:boot.user/numeric
boot.user=> (s/def ::numeric-coll (s/coll-of ::number))
:boot.user/numeric-coll
boot.user=> (gen/sample (s/gen ::numeric {::number gen/int}))
(-1 1.0 -1 NaN -1 2.5625 -1.5 -47 -13 24)
boot.user=> (gen/sample (s/gen ::numeric-coll {::number gen/int}))
([0 0 0 0 0 0 0 0 0] [-1 1 0 -1 -1 1 0] [-1 -2 1 -1 2 -2] [-2 -1 -2 -2 3 -2 1 -3] [-1 1 4 3 -4 4 -1 2 -4 -2 -4 4 -2 -4 0 -1] [1 -4 0 -1 0 -2 -1 -4 -2 -3 5 0 3 -1 -1 -3 -3 -1 -4] [3 -2 4 -3 -6 4 -3 3 2] [-7 -7 -1 -1 3 6 0 -7 0 -3 1] [] [9])
Filing now, thanks!