clojure-spec 2016-12-08

@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]))

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

Alex Miller (Clojure team) 2016-12-08T14:15:33.000834Z

(s/cat :1 #{1} :2 #{2} :3 #{3})

Alex Miller (Clojure team) 2016-12-08T14:15:56.000835Z

Or similar with s/tuple

But s/tuple can't be used within a regex, right?

Alex Miller (Clojure team) 2016-12-08T14:28:53.000837Z

Right

(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

šŸ˜‚ 4

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

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

ā˜ļø 1

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

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?

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.

(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?

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!