Fork me on GitHub
#clojure
<
2016-07-20
>
gareth09:07:03

has anyone successfully set S3 event notifications using Amazonica?

andreas-thoelke09:07:59

Hi! I would like to return the value of an expression if that value meets a predicate, otherwise I want to return a default value. Using a let and an if does the job:

(def cm [{:index 3} {:index 4}])

(let [v (-> cm last :index)]
  (if (integer? v) v -1))
or I can use a separate function:
(defn exp-if [v pred x] (if (pred v) v x))

(exp-if (-> cm last :index) integer? -1)
but I wonder if there is a more elegant/concise way to do this?

mpenet09:07:21

@alexmiller: is there a way to destructure all keys under a particular namespace under a single binding with the new ns key patch? Meaning I'd like to destructure by "groups" corresponding to kw namespace

mpenet09:07:01

I am turning config maps (multi level) schemas into clj.specs, making more use of namespaced keys and flattening the maps as a result, and often these namespaces correspond to a components options, so I'd end up having to (partial group-by (comp namespace key)) before feeding them to the components constructors.

mpenet09:07:31

I'd imagine something like this: (let [{:ns [a]} {:a/foo 1 :a/bar 2 :b/foo 3 :b/bar 4}] a) -> {:a/foo 1 :a/bar 2}}

mpenet09:07:08

but maybe it's a bit too weird, not sure

peterromfeld10:07:31

hi i have a empty? check, but possible values could also be long or keyword.. i wanna filter out all #{} [] "" nil

gon10:07:36

@andreas-thoelke take a look at fnil

andreas-thoelke11:07:56

Thanks @gon, I looked into fnil but can't see how I can use it here, as predicates return true/false and I think I would still need a let binding.

tap11:07:45

One idea: (some-fn #{#{} [] ""} nil?) (remove (some-fn #{#{} [] ""} nil?) [#{} [] "" nil 1 :a])

fabrao11:07:16

Hello all, I'm using clojure-mail to read an email message, is there any way to download the attachement?

Alex Miller (Clojure team)11:07:12

@mpenet that doesn't exist but you can :ns/keys [foo bar]

Alex Miller (Clojure team)11:07:00

Or you can partition-by namespace instead of destructuring

mpenet11:07:09

thx, I am doing more or less the latter for now

mpenet12:07:41

(via group-by since I need to look them up by key)

peterromfeld12:07:12

@tab that may work.. but... anything nice maybe?

peterromfeld12:07:01

i could also use multimethod to validate... which probably would be nicer.. but still is there nothing more concise and easy in the core?

peterromfeld12:07:08

im not sure why empty? throws exception on Long and keywords.. whats the reason behind it? empty? in my opinion should be just true/false ...

peterromfeld12:07:41

:keyword and 123455 is clearly not an empty value

peterromfeld12:07:43

i could also make ugly code and catch exceptions from empty? and if its long or keyword just pass

peterromfeld12:07:54

but again its ugly and doesnt feel that functional...

peterromfeld12:07:35

its not the lack of options to solve it.. its about nice and clean code.. and it doesnt make sense that empty? throws and exception, since Long and Keyword is a value and clearly not empty

peterromfeld12:07:11

and if there is another core function which solves the problem? (since i dont know the reasons behind why you would throw that exceptions, most liley implementation details)

peterromfeld12:07:32

i cant tell from implementation of empty? but i guess at that time there was no multi-method available, thats why its that incomplete

peterromfeld12:07:37

the biggest reason why you use a lisp like clojure is readability.. and from empty? i would believe everyone expects empty datastructure OR empty value of any form

gfredericks12:07:33

peterromfeld: "empty?" to me is a nonsensical question on non-collections

gfredericks12:07:01

it's an "I don't accept the premises of the question" sort of situation

gfredericks12:07:47

I suppose you could phrase the question as either "is this an empty collection?" or "is this collection empty?"

peterromfeld12:07:51

empty? = true = #{} [] "" nil '() {} ...

peterromfeld13:07:09

these are all empty values nvm data-structure or format

peterromfeld13:07:09

(empty? input) = is that input empty?

peterromfeld13:07:34

as you pointed out.. even looking at source.. the seq is the problem... 1234 is still sequential in my opinion.. its [1 2 3 4] keyword is a bit more difficult :keyword is kinda sequential from the perspective that it has a collection of chars in the end.. but [: k e y w o r d] is kinda weird

peterromfeld13:07:48

but then again.. as long its at least a sequence of chars.. it should be sequential!

peterromfeld13:07:03

for everything else you check the type

peterromfeld13:07:46

im afraid that i have to make my own multimethod to replace empty? and eventually do the same for seq.. i just cant understand why i have to do it and its not part of the core

Alex Miller (Clojure team)13:07:20

empty? takes a coll. if you pass it something that’s not a coll, then you should not expect good things to happen. In the future, there may be a spec that would tell you about this at dev time with instrumentation.

Alex Miller (Clojure team)13:07:01

same with seq. You might find the new seqable? predicate helpful.

Alex Miller (Clojure team)13:07:29

would you expect sensible things to happen with (+ 1 “a”) (if so, you may be using JavaScript :)

Alex Miller (Clojure team)13:07:14

if you back up to your actual problem, maybe there is some better solution. in general, I’d say it’s pretty weird to be in a situation where you would be trying to call empty? on something that’s not a coll.

peterromfeld13:07:34

im importing a csv, and translating it to datomic datastructure, since input of this csv is not trustable i need to validate most of the input

peterromfeld13:07:49

sometimes it ends up that i have and attr with empty value

peterromfeld13:07:11

which could be nil or empty coll or just empty string ""

peterromfeld13:07:30

i want to remove them before i make my transaction

peterromfeld13:07:08

i could push responsibility up and ask programm to only do attr val if there is an actual val

peterromfeld13:07:33

but thats much more complicated then just filter all empty vals

peterromfeld13:07:17

its not a problem of solving it.. like i said i can use my own multimethod or i can have some catch exceptions

peterromfeld13:07:27

or complicate the actual functions

peterromfeld13:07:13

its still that i would expect from empty? to only return true/false.. and its true if the provided value is empty

peterromfeld13:07:02

i love lisp/clojure because of readability... and empty? is missleading!

peterromfeld13:07:50

for my background, i have 0 java knowledge and whenever i need to java interop ive kinda a hard time... ive 0 javascript background and same with clojurescript.. whenever i need interop ive a hard time (got much better now).. i started with python, continued with elixir (still love that one) and are now active developer with clojure

peterromfeld13:07:45

and i love clojure because if you do naming correct, everyone can pick it up in few days

peterromfeld13:07:03

thats why have that logical issue with empty?

peterromfeld13:07:07

(empty? value)

codonnell13:07:28

@peterromfeld: personally I like the behavior of empty?. I'd like to know earlier rather than later if I'm passing something other than a collection where I'm expecting one. If you want the behavior you describe, you could do something like (fn [x] (if (seqable? x) (empty? x) false))

peterromfeld13:07:26

again i can rewrite empty? with my own implementation and multimethod which is much cleaner and more readable

peterromfeld13:07:05

why would you expect empty? to throw and exception if you pass a long or keyword?

peterromfeld13:07:11

whats the rationale behind it?

peterromfeld13:07:12

and why would it work on "" then?

codonnell13:07:29

I definitely think longs should not be treated natively as seqs. You suggest breaking them up by number, what what if the long is represented in a different base? It would have a completely different seq representation.

peterromfeld13:07:05

well (seq "asdf") => (\a \s \d \f)

peterromfeld13:07:28

why (seq 1234) not=> (\1 \2 \3 \4) ?

peterromfeld13:07:34

its all chars in the end

mpenet13:07:44

because it makes no sense

mpenet13:07:01

when would you want to have it behave like this?

codonnell13:07:14

16 = 16 in base 10. 16 = 10 as hexadecimal

codonnell13:07:20

which one should it be?

peterromfeld13:07:40

in this case just char sequence

peterromfeld13:07:52

because i dont treat it as a number

peterromfeld13:07:14

i dont care if hex or whatever in this case

peterromfeld13:07:21

thats not how i ask it to behave

peterromfeld13:07:27

i dont ask it to be a number

peterromfeld13:07:35

or hex or whatever

peterromfeld13:07:46

i just want to know if its something

peterromfeld13:07:51

whatever it is

peterromfeld13:07:23

you have enough math functions to validate your numbers

peterromfeld13:07:40

but in this case you dont care what the type is

peterromfeld13:07:57

you just want to know if it has a value

peterromfeld13:07:08

is the value empty? or not?

peterromfeld13:07:26

and from my logic at least 1234 is not an empty value

peterromfeld13:07:35

same goes for :keyword

peterromfeld13:07:07

now empty is tricky, because of these different types

peterromfeld13:07:18

thats why #{} or [] is empty

peterromfeld13:07:43

which works fine for most of the data types, like:

peterromfeld13:07:12

the issue is that there is no empty for keyword or long

peterromfeld13:07:20

and thats why you need multimethod

peterromfeld13:07:45

if you have a long or keyword.. there naturally is a value, because of course this value is what defines it to be a Long or Keyword

peterromfeld13:07:18

but im sure the time empty? got implemented, was before there was multimethod in clojure core

rickmoynihan13:07:01

On clojure 1.8 - what's the best way to test for seqable?

Alex Miller (Clojure team)13:07:36

there is a seqable? impl in core.incubator

Alex Miller (Clojure team)14:07:47

@peterromfeld the functions in core have expected input domains. the general approach is that that input domain is often not checked by the code and you may see exceptions or other confusing behavior if you violate expectations. you are not going to see these functions (now or ever) attempting to catch all possible input cases and coerce them to meaningful behavior. you may see (now that we have spec) the ability to catch those erroneous inputs earlier via instrumentation.

Alex Miller (Clojure team)14:07:57

empty? is doc’ed to work on coll, which (in core) means collections, which includes seqables (like strings)

Alex Miller (Clojure team)14:07:23

it makes no sense for a number to be seqable

Alex Miller (Clojure team)14:07:48

in the end, I think you will be more productive in trying to understand and internalize some of the design, rather than continuing with a mental model that is inaccurate and wishing it were so

Alex Miller (Clojure team)14:07:24

in your actual use case it seems that you have a variety of conditions that make an attribute “skippable” - those are specific to your problem and I think you should make a function for it. Then use standard functions to find and remove skippable attributes.

peterromfeld14:07:06

thanks ill go through that, i still think for current problem its easiest to just make my own whatevery-empty? multimethod and be done with it

Alex Miller (Clojure team)14:07:38

I’d recommend using or over a multimethod

peterromfeld14:07:44

im sorry i could not bring myself right now to read all of it, its just started explaining what the different datastructures are

peterromfeld14:07:10

late here right now

peterromfeld14:07:14

about to go to sleep

peterromfeld14:07:05

or i was thinking of, but well i could add a not to make the or work

peterromfeld14:07:31

the issue was that or to cancel execution would return a true where i would want a false

peterromfeld14:07:40

not sure fuck, time to sleep and look tomorrow

peterromfeld14:07:19

but still if i do (filter #(when-not (or (keyword? %) (number?)) (empty? %)) stuff) its super ugly

peterromfeld14:07:32

and kinda difficult to read when you come back a year later

Alex Miller (Clojure team)14:07:33

#(when-not (or (keyword? %) (number?)) (empty? %)) is a function - make it one and give it a name like valid-attr?

Alex Miller (Clojure team)14:07:19

(filter valid-attr? stuff) is very readable

peterromfeld14:07:28

there many versions to solve it, im still not convinced by the examples i got, why empty? behaves the way it does

peterromfeld14:07:26

(empty? val) look at it from logical perspective without any background to clojure or programming

Alex Miller (Clojure team)14:07:44

functions are defined over a domain of inputs. passing something outside that domain is a bug in your program.

peterromfeld14:07:08

ill just hack my way

peterromfeld14:07:27

like you can always control the input

Alex Miller (Clojure team)14:07:06

well you’re writing the code, so … you can

peterromfeld14:07:08

it was just a logical observation of the naming empty?

peterromfeld14:07:28

and what i think many people not that close to how clojure works, would interpret it

Alex Miller (Clojure team)14:07:40

empty? is logically a question you can ask of something that contains things. 5 does not contain things.

Alex Miller (Clojure team)14:07:03

right, but not a collection of values

peterromfeld14:07:16

"a" is a collection of values?

Alex Miller (Clojure team)14:07:26

as Clojure defines it, yes

Alex Miller (Clojure team)14:07:34

strings are treated as collections of chars

peterromfeld14:07:00

if thats the logical response..

peterromfeld14:07:22

123 is not a collection of chars?

Alex Miller (Clojure team)14:07:52

the Clojure reader reads Clojure source and produces Clojure data

Alex Miller (Clojure team)14:07:08

123 is read as the number 123, not the string “123"

peterromfeld14:07:15

in my world every "shit-whatever" is a char

peterromfeld14:07:43

you can interpret differnt chars to different types

peterromfeld14:07:47

numbers or whatever

Alex Miller (Clojure team)14:07:54

yes, and that’s different than Clojure data

peterromfeld14:07:57

but all thes types are a composition of chars

Alex Miller (Clojure team)14:07:10

you need to deal with the fact that your “data” is all strings

Alex Miller (Clojure team)14:07:24

either coerce to actual Clojure data, or deal with it as strings

peterromfeld14:07:45

you dont have the luxury to always have clojure datastructures as input

peterromfeld14:07:03

and even then it could get difficult to evaluate all of it

peterromfeld14:07:31

i have clojure map

peterromfeld14:07:46

but sometimes i dont have vals or empty vals

peterromfeld14:07:57

and sometimes they are Long or keywords

peterromfeld14:07:28

its just clash of perspectives

reefersleep14:07:37

Seems that way

reefersleep14:07:50

It was an interesting exchange of perspectives, though. Wish I had popcorn.

Alex Miller (Clojure team)14:07:55

data coercion is an inherent part of your problem domain

Alex Miller (Clojure team)14:07:46

Clojure does not magically solve that

peterromfeld14:07:12

i can just make my own multimethod or function to replace empty? to behave the way i expect it to

mccraigmccraig14:07:26

@peterromfeld: (->> yr-map (map (fn [[k v]] [k (str v)])) (into {})) now all your vals are strings !

peterromfeld14:07:35

thanks alex, you gave at least quite much more explanations 😛

peterromfeld14:07:50

i guess there could be things changed underlying to it

Alex Miller (Clojure team)14:07:50

if your input is strings, you need to supply some interpretation of those strings. csv is inherently poor at this. there is no way to distinguish the string “123” and a number 123 as CSV has no explicit schema. Or false / “false” or nil / “”. It is not fair to push that interpretation (which is specific to your problem) into core functions.

peterromfeld14:07:11

no ive a map of clojure datastructure

peterromfeld14:07:19

its just most attrs have good values

peterromfeld14:07:26

but some have shit which i wanna filter

Alex Miller (Clojure team)14:07:37

“good” implies interpretation - and that’s up to you

peterromfeld14:07:39

empty?.. #{} "" nil []

peterromfeld14:07:49

to make the underlying stuff work in a different way to get to same result, it requires so many more lines or maybe i just do it complete wrong

peterromfeld14:07:31

i have not heard a solid explanation why (empty? 123) should throw an exception

peterromfeld14:07:41

same for (empty? :key)

Alex Miller (Clojure team)14:07:01

omg, for the third time: functions are defined for a domain of inputs and those values are outside the domain.

peterromfeld14:07:24

its a fucking function with a name

akiva14:07:30

I’m imagining this as a job interview.

peterromfeld14:07:38

im not in java here

peterromfeld14:07:42

with objects and shit

Alex Miller (Clojure team)14:07:46

why doesn’t + work on keywords and numbers?

Alex Miller (Clojure team)14:07:03

why doesn’t assoc work with strings?

peterromfeld14:07:14

because + has a very strong meaning

peterromfeld14:07:17

its for numbers

Alex Miller (Clojure team)14:07:21

ALL of these have a strong meaning

peterromfeld14:07:22

back to naming..,.

Alex Miller (Clojure team)14:07:27

it’s in the docstring

Bryan14:07:35

Definition of empty?:

(defn empty?
  "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  {:added "1.0"
   :static true}
  [coll] (not (seq coll)))
It's that way because it's defined that way.

peterromfeld14:07:57

why is a sting a coll?

Bryan14:07:16

123 and :key aren't collections (as defined by the language), so, it throws an exception

Alex Miller (Clojure team)14:07:18

that is not an accidental choice of words - arg names have a specific meaning in core docstrings

Alex Miller (Clojure team)14:07:31

a string is seqable (can provide a seq) of chars

peterromfeld14:07:44

its a sequence of chars

codonnell14:07:17

[] is a sequence of chars, too

codonnell14:07:29

but it has two chars

peterromfeld14:07:57

its vector, empty one

Bryan14:07:03

"[]" <- is a string as defined by the language [] is an empty vector as defined by the language

peterromfeld14:07:16

"[]" is different to []

codonnell14:07:37

the point is type matters in clojure

peterromfeld14:07:39

one is a sting with a value

peterromfeld14:07:44

the other one is empty vector

peterromfeld14:07:12

thats also my point

peterromfeld14:07:23

[] = empty vector

peterromfeld14:07:28

"" = empty sting

peterromfeld14:07:39

nil = empty whatever (nothing)

peterromfeld14:07:44

#{} = empty set

peterromfeld14:07:51

123 = not empty

peterromfeld14:07:56

:key = not empty

Alex Miller (Clojure team)14:07:32

on the last two, I would say you are asking an invalid question

peterromfeld14:07:44

no the value is it empty or not

peterromfeld14:07:52

there is a value

Bryan14:07:58

vectors, strings, and sets are all collections, so they can have the property of "emptyness". 123 is a literal and so can't be empty (as a side note, how would you write an empty literal?), :key is a keyword/function and also doesn't have the property of "emptyness"

Alex Miller (Clojure team)14:07:04

that’s not what empty? says it does

peterromfeld14:07:21

there is no empty Long or Keyword

peterromfeld14:07:48

if there is a value (which there is by just being one of these types) its not empty anymore

Bryan14:07:09

>Returns true if coll has no items Actually, that's exactly what empty says it does. Since 123 and :key aren't collections, they are undefined for this function and thus, you get a traceback.

peterromfeld14:07:57

the way "string" is different to 1235 is just implementation detail

peterromfeld14:07:17

from logic its still just a sequence of chars.. both

akiva14:07:54

They’re displayed as a sequence of characters. Underneath the hood, they’re handled differently.

peterromfeld14:07:08

implementation detail

Alex Miller (Clojure team)14:07:10

this is at the foundation of Clojure/Lisp. the reader converts your code (characters) into data, that can be manipulated by your program.

peterromfeld14:07:21

so what would be your harm, if empty? would say false on Long and Keyword?

scriptor14:07:38

strings should not be logically considered a sequence of characters

scriptor14:07:56

considering "sequence" has a very specific meaning in clojure

peterromfeld14:07:13

fuck that specific implementation details

peterromfeld14:07:24

and its about meaningful NAMES

peterromfeld14:07:46

i can work around it.. like i said.. its just a naming i just cant agree.. and you have not given me so far a valid logical explanation why you would do that..

peterromfeld14:07:51

its just excuses

rickmoynihan15:07:17

thanks for the core.incubator tip alexmiller

peterromfeld15:07:59

i understand underlying implementation complications and why you may would differntiate these things from implementation detail view

peterromfeld15:07:29

but from a non professional view, just about naming and general logic

Alex Miller (Clojure team)15:07:32

one man’s excuses are another team’s 10 years of design efforts

peterromfeld15:07:35

i cant understand it

scriptor15:07:47

are you aware that empty? calls seq on its argument?

peterromfeld15:07:04

with nil? and seq

peterromfeld15:07:19

and i believe it was done before multimethods

Alex Miller (Clojure team)15:07:28

that has nothing to do with it

Alex Miller (Clojure team)15:07:39

if it was defined now, it would be defined the same

scriptor15:07:48

there is no nil?

scriptor15:07:57

(defn empty?
  "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  {:added "1.0"
   :static true}
  [coll] (not (seq coll)))

peterromfeld15:07:22

(defn ^boolean empty?
  "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  [coll] (or (nil? coll)
             (not (seq coll))))

peterromfeld15:07:42

im not so sure about that

peterromfeld15:07:05

from a outstanding eye, without any clojure knowledge but just common sense and logic

peterromfeld15:07:09

it doesnt make sense

scriptor15:07:42

@peterromfeld: where did you get that code from

scriptor15:07:36

not the version number, where did you find that

Alex Miller (Clojure team)15:07:53

the code @scriptor posted is the code, and has been since at least 2008

peterromfeld15:07:55

oh no just : CLOJURE_VERSION=1.7.0

scriptor15:07:35

oh, I see the confusion here

scriptor15:07:43

what you posted is the clojurescript implementation

peterromfeld15:07:09

it still doesnt change things lol

peterromfeld15:07:17

this one or is useless

peterromfeld15:07:30

its unessacary code

peterromfeld15:07:50

(nil? x) == (not (seq x)) for most of the time

Alex Miller (Clojure team)15:07:54

there may be perf reasons for it in cljs

peterromfeld15:07:26

of course left only works on nil 😉

scriptor15:07:45

@alexmiller: possibly, but cljs's seq already has a check for (when-not (nil? coll)) http://cljs.github.io/api/cljs.core/seq

peterromfeld15:07:03

(def
 ^{:arglists '(^clojure.lang.ISeq [coll])
   :doc "Returns a seq on the collection. If the collection is
    empty, returns nil.  (seq nil) returns nil. seq also works on
    Strings, native Java arrays (of reference types) and any objects
    that implement Iterable. Note that seqs cache values, thus seq
    should not be used on any Iterable whose iterator repeatedly
    returns the same mutable object."
   :tag clojure.lang.ISeq
   :added "1.0"
   :static true}
 seq (fn ^:static seq ^clojure.lang.ISeq [coll] (. clojure.lang.RT (seq coll))))

peterromfeld15:07:36

it does what it says

peterromfeld15:07:43

its still naming

peterromfeld15:07:28

why is (empty? "") working but not with Long or Keyword... yes seq says exactly why.. but its still naming clash for me

peterromfeld15:07:57

i dont have the object java background, so i only understand seq works on char sequence, but be careful not works on charsequence that starts with : or is only numerical

Alex Miller (Clojure team)15:07:16

those are not char sequences

Alex Miller (Clojure team)15:07:24

they are numbers and keywords

peterromfeld15:07:31

what is a character? what is a sequence?

peterromfeld15:07:43

every fucking symbol is a character

peterromfeld15:07:54

its characters

scriptor15:07:57

are you trying to argue that every data type is a character

Alex Miller (Clojure team)15:07:04

no, they are not once the reader has read them

peterromfeld15:07:13

thats why you have datastructure and types

peterromfeld15:07:28

so you dont have to fuck around with random char sequences

peterromfeld15:07:34

some of them have higher meaning

jeffh-fp15:07:51

@peterromfeld: your argumentative communication is really off-putting when people are being so patient with you

Alex Miller (Clojure team)15:07:58

you have a fundamental misunderstanding here about how Clojure works

scriptor15:07:06

and how types in general work

Alex Miller (Clojure team)15:07:38

the Clojure reader reads source (characters) into Clojure data. At that point :foo is not a string, it is a keyword

Alex Miller (Clojure team)15:07:52

5 is not a character or a string, it is a number

scriptor15:07:00

it makes sense that (seq "foo") returns a sequence of characters, it does not make sense that (seq 1234) returns a sequence of digits

Alex Miller (Clojure team)15:07:08

The reader page above defines how that is done

Alex Miller (Clojure team)15:07:29

all Clojure functions take and return Clojure data

peterromfeld15:07:00

1234 is still a sequence of single digits put together

Alex Miller (Clojure team)15:07:12

when written in a file or typed into a repl yes

Alex Miller (Clojure team)15:07:22

but then the reader reads it as an atomic number

bronsa15:07:23

010 evaluates to 8, should it be "010" or "8"? your interpretation simply doesn't make any sense

Alex Miller (Clojure team)15:07:54

2r010101 is another representation, also read as a number

peterromfeld15:07:21

we are using a high level language which should abstract most shit, to down that deep?

scriptor15:07:28

this is not "deep"

scriptor15:07:32

this is basic programming

peterromfeld15:07:57

well i can do quite much without this "basic programming"

peterromfeld15:07:07

by using high level abstraction langs

scriptor15:07:28

every other language also treats 1234 as an atomic value

scriptor15:07:32

unless you're talking about PHP

bronsa15:07:32

what's a language that interprets 123 as a collection of 1 2 and 3 in some contexts?

peterromfeld15:07:54

i never thought about theses things in other languages before

peterromfeld15:07:04

because i did not have that level of readability

peterromfeld15:07:43

in any other language i just go with it, wtf thats how it is

joost-diepenmaat15:07:01

I’m trying to figure out if it’s possible to specify in clojure.spec that some function has an equivalent other implementation that should return the same values given the same inputs. I’m building 2 implementations of a protocol that I would like to check against each other.

Alex Miller (Clojure team)15:07:40

@joost-diepenmaat: that is a good and wise question, which may some day be provided within spec

joost-diepenmaat15:07:40

Or should I use some mix of clojure.spec and test.check if I want to do that?

bronsa15:07:32

@peterromfeld: it seems like you're either having a severe misunderstanding of how abstractions should work or you're just inexperienced, either way what you're saying doesn't make sense. I'd suggest trusting ever language designer ever to be right on this one.

joost-diepenmaat15:07:45

thanks @alexmiller 😄 I guess that means I should read up on test.check then 🙂

codonnell15:07:55

@joost-diepenmaat: (s/fdef fname :fn #(= (:ret %) (apply other-fn (:args %)))) should work I think?

peterromfeld15:07:44

im a bit inexpirienced, the thing i love most about clojure is maintainablity as long as you get naming right (and how easy to teach new employees if naming is good)

peterromfeld15:07:09

so even if you dont know that much about programming, you can get started quick in clojure with good names

peterromfeld15:07:39

names that make sense even without knowing about implementation details

Alex Miller (Clojure team)15:07:59

I’d suggest that the names we’ve been talking about are good names and that your semantic mismatch is due to a misunderstanding of how Clojure works, as far as I can tell

scriptor15:07:08

this isn't a clojure thing, most sensible languages view strings as something that can be turned into a sequence, and longs as atomic values that cannot

bronsa15:07:19

defined input sets are not implementation details. they're part of the definition of a function. empty? is defined and documented to work on collections, which numbers are not

scriptor15:07:53

what you consider an "implementation detail" is what others would consider an expected convention

peterromfeld15:07:55

i still cant understand how string is a collection and numbers not

scriptor15:07:11

and most programmers would be confused if (seq 1234) somehow turned it into a sequence of digits

peterromfeld15:07:44

ok then im just to unexperienced

peterromfeld15:07:15

its just the logic that this 12345 and "asdf" is both a seq of chars for me here visual and logical

scriptor15:07:27

there are languages that have tried to coerce numbers as digit-sequences, typically this has not worked out well

scriptor15:07:58

because the vast majority of the time we don't want to use 1234 as a list of '(1 2 3 4)

peterromfeld15:07:03

" " just visualises a string for me

peterromfeld15:07:36

i neither want to

peterromfeld15:07:52

i just wanna check if there is a value of meaning

peterromfeld15:07:22

i dont wanna transact a empty attribute

peterromfeld15:07:04

ya need to figure out different, or make my own valid? instead of empty?

peterromfeld15:07:40

maybe call it not-seq? insead of empty?

peterromfeld15:07:44

would welcome it

scriptor15:07:08

what do you want to check

peterromfeld15:07:17

if a given value is empty

peterromfeld15:07:28

but given value can also be Long or Keyword

akiva15:07:47

But longs and keywords are never empty, so it’d always return false for them.

codonnell15:07:47

@joost-diepenmaat: seems to work here:

=> (defn my+ [x y] (+ x y))
=> (s/fdef my+ :args (s/tuple number? number?) :fn #(= (:ret %) (apply + (:args %))))
=> (stest/check `my+)
({:spec #object[clojure.spec$fspec_impl$reify__13789 0x3523619d "[email protected]"], :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1469028616727}, :sym user/my+})

scriptor15:07:06

have you encountered a point in your code where you've needed to treat certain longs or keywords as empty?

akiva15:07:42

Because empty? isn’t meant to be used on non-collections and keywords and longs aren’t collections. It’s a misuse of the function.

peterromfeld15:07:55

i dont need to treat them by themself as empty, but i have a map with eventual empty vals, and wanna remove the attrs with empty vals

scriptor15:07:56

@peterromfeld: if you ever end up calling empty? on a keyword or long, chances are there is a bug somewhere in your code

scriptor15:07:14

meaning, where your code is expecting a collection it's getting one of those instead

mccraigmccraig15:07:41

@peterromfeld: you can define your own, say, IValid protocol with a (valid? [x]) method and implement that for all the types you care about

joost-diepenmaat15:07:52

@codonnell thanks, that looks usable. I need to refactor a few things in order to make that work with the protocols involved

peterromfeld15:07:56

yeah i know i can my own multimehtod

bronsa15:07:25

empty seqs are seqs, not-seq? would be a completely wrong name

peterromfeld15:07:51

its just the general meaning of empty? if you dont think too depp into the language or others, what would a little kid understand by a function called empty?

peterromfeld15:07:02

i know how to fic my issue

mccraigmccraig15:07:13

if you consider ZF set-theoretic representation of natural numbers, then the concept of an empty number does makes sense

peterromfeld15:07:15

its really just about the naming for empty?

mccraigmccraig15:07:42

but that's not clojures representation, so it doesn't make sense in clojure

Alex Miller (Clojure team)15:07:44

I think empty inherently involves the notion of containment based on its English definition

bronsa15:07:55

I suggest dropping this conversation as it's clearly not going anywhere

Alex Miller (Clojure team)15:07:20

and that seems like an exact match to what empty? means in Clojure

Alex Miller (Clojure team)15:07:36

would a little kid understand the question “is the 5 empty?"

Alex Miller (Clojure team)15:07:47

that is a nonsensical question

peterromfeld15:07:30

ok ill stop sorry

peterromfeld15:07:28

i guess ill do (not-value? val) and it will be true if its an empty datastructure or empty sting or nil

peterromfeld15:07:07

i like to make use of nil if something is not true or no return value, of course you still wanna throw on unexpected behaviour.. but making use of nil and sometimes you have empty datasets depending on fucntion, and then you go ove the whole data and remove the empty shit looked very convenient, just have to replace empty? with my not-value?

dg15:07:55

It's hard for me to imagine a situation where you would want to treat an empty string the same way as nil

codonnell16:07:54

@dg: I consume an api that sometimes returns an empty string instead of null to indicate null values. I won't argue that it's good practice, but it's not an unimaginable situation.

dg16:07:57

Yikes. But you're right, I was assuming @peterromfeld had control over his api

brian_mingus19:07:01

can tree-seq navigate a map of vectors of maps of vectors etc..?

gfredericks19:07:18

it can navigate anything if you tell it how to

gfredericks19:07:37

(tree-seq coll? seq ...) works pretty good in a lot of cases

radon20:07:36

Why do

(deftype Foo [] Object (toString [this] "Foo"))
and
(deftype Foo [])
(extend-type Foo Object (toString [this] "Foo”))
produce different behavior? The first version works as expected
(str (Foo.)) => "Foo"
while the second throws
IllegalArgumentException class java.lang.Object is not a protocol  clojure.core/extend (core_deftype.clj:769)

seancorfield20:07:46

According to the docstrings, deftype works with protocols or interfaces or Object, whereas extend-type (via extend) only works with protocols.

radon21:07:03

Oh! Silly me. Should have read through those first.

radon21:07:25

Is there any way to change the str representation of a type after it has been created, or do you absolutely have to do it in the deftype?

niquola21:07:30

Hi all, i want to uberjar and aot and then run all tests. I'm calling (clojure.test/run-tests testedns) in main, but it only prints deftest titles and does not run tests.

niquola21:07:18

If i run from repl - everything ok - tests run, looks like aot or jar eats my tests

Alex Miller (Clojure team)21:07:16

@radon no - the class underlying the type has been created with the method in it already (that’s why you can’t change it later). Of course you could have the impl in deftype call a function that you redefine later.

Alex Miller (Clojure team)21:07:54

@nicola uberjars don’t typically include the tests afaik?

niquola21:07:26

I know, but i want to build jar, test and deploy 🙂

radon21:07:36

I would run tests before making an uberjar—after all, what are you going to do with an uberjar whose code doesn’t work?

pdlug21:07:48

What’s the easiest way to remove the namespace from all keyword keys in a map? (think map used w/ spec but now need to serialize w/o namespaced keywords)

radon21:07:12

Just make your deployment pipeline something like lein test && lein uberjar && <deploy>.

niquola21:07:28

@radon It's like you recommend now. But lein is slow 😞 I wonna build it once

radon21:07:53

Surely you won’t be deploying so often that the 5-second startup of lein would be an issue?

radon21:07:04

In my experience, most of the startup delay is due to loading code.

radon21:07:17

Oh, well I suppose all the code would be loaded twice.

radon21:07:36

So, that’s a reasonable point.

radon21:07:51

But I think it is very bad practice to include tests in the uberjar.

radon21:07:06

Tests are for development, and you would not include development code in the production build.

niquola21:07:27

At least it's original 🙂

radon21:07:35

Perhaps lein do test, uberjar would speed things up?

richiardiandrea21:07:07

newbie question, is there a way to get a symbol from a var? Some sort of unresolve?

niquola21:07:53

@radon

lein do configure tmp/config.edn, migrate, test-db, test

radon21:07:29

Well, you could just stick uberjar onto the end. That would eliminate the duplicate lein startup time.

niquola21:07:01

I will fight little bit for build,test, deploy, then rollback to test,build,deploy 🙂

richiardiandrea21:07:24

self-answer by looking at the source, I can use .sym and .ns, akin to this https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L130

richiardiandrea21:07:50

(symbol (str (.ns v) "/" (.sym v)))

richiardiandrea21:07:47

repl is power 😄

niquola21:07:19

@radon (when load-test ....) everywhere in clojure.test, i think lein set it to false while uberjar

radon21:07:35

Ah yes, that would make sense.

radon21:07:49

But why would you want to run your tests after you build?

radon21:07:04

That just makes it take longer to tell if the tests pass or not.

radon21:07:22

Unless you are having trouble with normal vs. AOT compilation.

niquola21:07:21

@radon i will think about this, thank you for getting me back from my fantasy 🙂

brian_mingus21:07:27

^ integration tests are run after build

radon21:07:53

Right, but I would guess that integration tests would not be run from within lein test?

radon21:07:58

Or are they?

niquola21:07:30

They are 🙂

niquola21:07:44

I have postgresql failover & dockers management inside 🙂

radon21:07:29

In that case, I guess you should separate the unit and integration tests (I think clojure.test has support for enabling/disabling labeled groups of tests)…

niquola21:07:13

I found problem, aot'ed namespaces are lazy so (all-ns) is empty. If i require test namespaces everything works

niquola22:07:54

We need

(clojure.core/split-by pred coll)

pataprogramming22:07:57

I'm looking for some help figuring out what's going on with a 4Clojure problem (#150, palindromic numbers). My solution works fine on my machine, and the longest test case completes in around 55 ms, with all cases together taking around 140 ms. I know that 4Clojure is running on a fairly ancient version of clojure. Is there a behavior change to, e.g., laziness that would greatly change the performance characteristics of my solution? Or is the timeout really shorter than 55 ms? My solution attempt is at https://www.refheap.com/121787 - I get the same timeout on tryclj.