03:52
rajivr has joined #nix-lang
07:47
mpickering has quit [Ping timeout: 268 seconds]
07:49
mpickering has joined #nix-lang
12:23
__monty__ has joined #nix-lang
15:31
ddellacosta has joined #nix-lang
15:55
ddellacosta has quit [Ping timeout: 246 seconds]
17:47
Profpatsch has joined #nix-lang
17:47
<
Profpatsch >
okay, you got me
17:47
<
infinisil >
> :v mergeAttrsWith
17:47
<
{^_^} >
mergeAttrsWith = op: a: b: a // b // intersectAttrsWith op a b
17:48
<
infinisil >
> :v intersectAttrsWith
17:48
<
{^_^} >
intersectAttrsWith = op: a: b: lib.mapAttrs (n: bv: op a.${n} bv) (builtins.intersectAttrs a b)
17:48
<
infinisil >
This is what I wrote recently
17:48
<
infinisil >
Those take an `op :: Value -> Value -> Value` which is called on collisions
17:48
<
infinisil >
Could put a `throw` in there
17:48
<
Profpatsch >
what does intersectAttrs do?
17:49
<
Profpatsch >
Just an intersect?
17:49
<
infinisil >
What you'd expect, intersects attribute sets, preferring the right side on collisions
17:50
<
Profpatsch >
mergeAttrsWith looks like it’s doing a bit more work than necessary
17:51
<
infinisil >
I'm not sure if it can be improved
17:52
<
Profpatsch >
infinisil: do attrsets force WHNF on values?
17:53
<
infinisil >
> builtins.seq { x = throw ""; } null
17:54
<
Profpatsch >
> builtins.seq { "${throw ""}" = 32; } null
17:54
<
Profpatsch >
> builtins.seq { "${throw "foo"}" = 32; } null
17:55
<
infinisil >
Hehe, guess it doesn't show empty errors
18:21
kalbasit has joined #nix-lang
18:21
<
Profpatsch >
how about
18:21
<
Profpatsch >
> mergeAttrsUnique = left: right:
18:21
<
{^_^} >
error: syntax error, unexpected ';', at (string):234:33
18:21
<
Profpatsch >
let intersect = lib.intersectLists (lib.attrNames left) (lib.attrNames right); in
18:21
<
Profpatsch >
assert
18:21
<
Profpatsch >
lib.assertMsg (intersect == [])
18:21
<
Profpatsch >
(lib.concatStringsSep "\n" [
18:21
<
Profpatsch >
"mergeAttrsUnique: keys in attrset overlapping:"
18:21
<
Profpatsch >
"left: ${lib.generators.toPretty {} (lib.getAttrs intersect left)}"
18:21
<
Profpatsch >
"right: ${lib.generators.toPretty {} (lib.getAttrs intersect right)}"
18:21
<
Profpatsch >
left // right;
18:21
<
Profpatsch >
> mergeAttrsUnique = left: right: let intersect = lib.intersectLists (lib.attrNames left) (lib.attrNames right); in assert lib.assertMsg (intersect == []) (lib.concatStringsSep "\n" ["mergeAttrsUnique: keys in attrset overlapping:" "left: ${lib.generators.toPretty {} (lib.getAttrs intersect left)}" "right: ${lib.generators.toPretty {} (lib.getAttrs intersect right)}"]); left // right;
18:21
<
{^_^} >
error: syntax error, unexpected ';', at (string):234:387
18:22
<
Profpatsch >
> assert true; "foo"
18:22
<
Profpatsch >
> x = assert true; "foo"
18:22
<
Profpatsch >
> mergeAttrsUnique = left: right: let intersect = lib.intersectLists (lib.attrNames left) (lib.attrNames right); in assert lib.assertMsg (intersect == []) (lib.concatStringsSep "\n" ["mergeAttrsUnique: keys in attrset overlapping:" "left: ${lib.generators.toPretty {} (lib.getAttrs intersect left)}" "right: ${lib.generators.toPretty {} (lib.getAttrs intersect right)}"]); left // right
18:22
<
{^_^} >
mergeAttrsUnique defined
18:23
<
Profpatsch >
mergeAttrsUnique { foo = "bar"; } { foo = 42; }
18:23
<
Profpatsch >
>mergeAttrsUnique { foo = "bar"; } { foo = 42; }
18:23
<
Profpatsch >
> mergeAttrsUnique { foo = "bar"; } { foo = 42; }
18:23
<
{^_^} >
assertion (((lib).assertMsg (intersect == [ ])) (((lib).concatStringsSep "\n") [ ("mergeAttrsUnique: keys in attrset overlapping:") (("left: " + (((lib).generators.toPretty { }) (((lib).getAttrs...
18:23
<
Profpatsch >
doesn’t print the trace
18:23
<
Profpatsch >
> mergeAttrsUnique { foo = "bar"; } { bar = 42; }
18:23
<
{^_^} >
{ bar = 42; foo = "bar"; }
18:32
<
infinisil >
Profpatsch: Seems like a subset of mergeAttrsWith behavior
18:33
<
Profpatsch >
infinisil: yeah, once that lands it could be refactored
18:33
<
infinisil >
And with O(n^2) runtime
18:33
<
infinisil >
(the lib.intersectLists)
18:34
<
Profpatsch >
I think it would make sense to annotate all runtimes and check whether there’s any low-hanging fruit
18:35
<
Profpatsch >
Esp the attrsets stuff
18:35
<
Profpatsch >
free real estate
18:35
<
infinisil >
All the tail's in attrsets.nix would be nice to avoid
18:35
<
Profpatsch >
some of the stuff in deprecated.nix is horrible lol
18:36
<
Profpatsch >
uhhh, tail is O(n)?
18:36
<
Profpatsch >
infinisil: I said in another channel that a lazy tuple might be a good idea
18:36
<
Profpatsch >
builtins.tuple { _1 = …; _2 = … }
18:36
<
infinisil >
That's just a list :)
18:36
<
Profpatsch >
which translates to a space-efficient repr in newer nixes
18:37
<
Profpatsch >
Yeah, and then we could build actually lazy cons-lists
18:37
<
Profpatsch >
which are somewhat nice in their space-usage as long as you don’t do … stuff
18:37
<
infinisil >
We can already
18:38
<
infinisil >
One change to Nix I want to make soon is allow .<number> for accessing list elements, which will make this nicer
18:38
<
Profpatsch >
well, it’s an optimization for { car = …; cdr = … } which I’d guess uses some space to save the labels
18:38
<
infinisil >
> [0 1].0
18:38
<
{^_^} >
attempt to call something which is not a function but a list, at (string):459:1
18:38
<
Profpatsch >
infinisil: but that evaluates the cells to WHNF
18:38
<
infinisil >
> builtins.seq [ (throw "nope") ] null
18:38
<
Profpatsch >
It doesn’t?
18:38
<
infinisil >
Nope, lists are lazy in elements
18:39
<
Profpatsch >
> builtins.length [ (throw "nope") ] null
18:39
<
{^_^} >
attempt to call something which is not a function but an integer, at (string):459:1
18:39
<
Profpatsch >
> builtins.length [ (throw "nope") ]
18:39
<
Profpatsch >
puck: you lied to me!!! :D
18:40
<
Profpatsch >
we have stuff like recursiveUpdateUntil which is used in only two places in nixpkgs
18:41
<
Profpatsch >
lol, it actually has a release note for 18.09 because it was buggy
18:41
<
infinisil >
> fastnixarray = import <nixbotlib/fastnixarray>
18:41
<
{^_^} >
fastnixarray defined
18:41
<
infinisil >
> fastnixarray
18:41
<
{^_^} >
{ count = 4; emptyArray = <CODE>; foo = <CODE>; get = <CODE>; lib = <CODE>; measure = <CODE>; seqListElems = <CODE>; set = <CODE>; test = <CODE>; toArray = <CODE>; toList = <CODE>; }
18:42
<
infinisil >
> fastnixarray.toArray (lib.range 0 100)
18:42
<
{^_^} >
{ capacity = <CODE>; contents = [ [ [ [ 0 1 2 3 ] [ 4 5 6 7 ] [ 8 9 10 11 ] [ 12 13 14 15 ] ] [ [ 16 17 18 19 ] [ 20 21 22 23 ] [ 24 25 26 27 ] [ 28 29 30 31 ] ] [ [ 32 33 34 35 ] [ 36 37 38 39 ] [ 40...
18:42
<
infinisil >
> fastnixarray.toArray (lib.range 0 10)
18:42
<
{^_^} >
{ capacity = <CODE>; contents = [ [ 0 1 2 3 ] [ 4 5 6 7 ] [ 8 9 10 null ] [ ] ]; empty = <CODE>; }
18:42
<
infinisil >
Using lists for this as well :)
18:44
<
infinisil >
> set 1000 "foo" (fastnixarray.toArray (lib.range 0 10))
18:44
<
{^_^} >
undefined variable 'set' at (string):460:1
18:44
<
infinisil >
> fastnixarray.set 1000 "foo" (fastnixarray.toArray (lib.range 0 10))
18:44
<
{^_^} >
{ capacity = <CODE>; contents = [ [ <CODE> ] [ ] [ ] [ [ ] [ ] [ ] [ [ ] [ ] [ [ ] [ ] [ "foo" null null null ] [ ] ] [ ] ] ] ]; empty = <CODE>; }
18:44
<
infinisil >
> :p fastnixarray.set 1000 "foo" (fastnixarray.toArray (lib.range 0 10))
18:44
<
{^_^} >
{ capacity = 1024; contents = [ [ [ [ [ 0 1 2 3 ] [ 4 5 6 7 ] [ 8 9 10 null ] [ ] ] ] ] [ ] [ ] [ [ ] [ ] [ ] [ [ ] [ ] [ [ ] [ ] [ "foo" null null null ] [ ] ] [ ] ] ] ]; empty = null; }
18:44
<
infinisil >
> :p fastnixarray.set 10000 "foo" (fastnixarray.toArray (lib.range 0 10))
18:45
<
{^_^} >
{ capacity = 16384; contents = [ [ [ [ [ [ [ 0 1 2 3 ] [ 4 5 6 7 ] [ 8 9 10 null ] [ ] ] ] ] ] ] [ ] [ [ ] [ [ ] [ ] [ ] [ [ [ ] [ [ "foo" null null null ] [ ] [ ] [ ] ] [ ] [ ] ] [ ] [ ] [ ] ] ] [ ] ...
18:47
kalbasit_ has joined #nix-lang
18:47
rajivr has quit [Quit: Connection closed for inactivity]
18:48
kalbasit has quit [Ping timeout: 256 seconds]
18:51
kalbasit_ has quit [Ping timeout: 256 seconds]
18:52
kalbasit has joined #nix-lang
18:59
kalbasit has quit [Remote host closed the connection]
19:01
kalbasit has joined #nix-lang
19:09
<
puck >
<Profpatsch> puck: you lied to me!!! :D <- you still can't make a list that's infinitely long :p
19:09
ddellacosta has joined #nix-lang
19:10
<
Profpatsch >
puck: sure, just use car/cons cells
19:10
<
Profpatsch >
Or does that hit the recursion depth?
19:12
<
Profpatsch >
infinisil: I’m just noticing, (listToAttrs (map ()) is everywhere
19:12
<
Profpatsch >
Now I wonder how much we could save if we made that into a builtin instead of listToAttrs
19:12
<
infinisil >
Well listToAttrs is a builtin and so is map, so I don't expect a lot
19:12
<
infinisil >
I guess one less list allocation though
19:13
<
Profpatsch >
mapAttrs['], genAttrs and zipAttrsWithNames use it just in attrsets.nix
19:14
<
Profpatsch >
I guess ideally there would be some kind of rewriting system that does these automatically
19:14
<
infinisil >
Hm yeah
19:14
<
Profpatsch >
Same with the listToAttrs … attrsToList
19:15
<
infinisil >
Hm wait
19:16
<
Profpatsch >
well, maybe more in a sense of rewriting rules.
19:16
<
infinisil >
builtins.sort builtins.lessThan is optimized
19:16
<
infinisil >
But not builtins.sort (a: b: a < b) I think
19:17
<
infinisil >
TIL about builtins.lessThan
19:17
<
Profpatsch >
Maybe hnix can do AST-based rewrites
19:17
<
Profpatsch >
But I guess I’m faster with helm-edit :P
19:17
<
infinisil >
Rewrite it how though?
19:17
<
infinisil >
Need a new builtin for the listToAttrs map thing
19:18
<
Profpatsch >
I mean rewrite as in go through nixpkgs and rewrite all occurences
19:18
<
infinisil >
I think this internal rewriting might be nicer because of this
19:18
<
infinisil >
Yeah but to what
19:18
<
Profpatsch >
the lib function
19:18
<
Profpatsch >
I wonder how fast the lib lookup for `builtins ? foo` is
19:19
* infinisil
doesn't get it, you want to rewrite `listToAttrs (map ..)` with which lib function?
19:19
<
Profpatsch >
because that is something we could easily remove statically the first time the evaluator passes it
19:19
<
infinisil >
Except builtins can change :P
19:20
<
infinisil >
let builtins = ...; in ...
19:21
<
Profpatsch >
infinisil: I mean rewrite textually first in nixpkgs, to the lib definition, then use `builtins.mapListToAttrs or <definition>` once the builtin exists
19:22
<
infinisil >
Ah got it
19:22
<
Profpatsch >
And then the nix evaluator can have a static shortcut that rewrites these `builtins.foo or foo-def` terms to `builtins.foo` if the builtin exists
19:22
<
Profpatsch >
So that it doesn’t have to go through the branch everytime the function is called
19:22
<
Profpatsch >
e.g. for concatMap = builtins.concatMap or (f: list: concatLists (map f list));
19:23
<
Profpatsch >
which might be quite substantial? Maybe not
19:23
<
Profpatsch >
But feels like an easy win
19:24
<
infinisil >
Profpatsch: Hmm, what if there's some function optimizer in general
19:24
<
infinisil >
Which can detect these kinds of optimizations automatically
19:24
<
Profpatsch >
that’s a JIT, no?
19:24
<
Profpatsch >
But that requires a complete rewrite of the evaluator
19:24
<
infinisil >
Hmm well it wouldn't compile it to machine code presumably
19:24
<
infinisil >
Or would it
19:25
<
Profpatsch >
I think JITs usually work on a bytecode representation firts
19:25
<
Profpatsch >
but I guess why not, libjit exists
19:25
<
Profpatsch >
Like how Emacs is gonna be 3 times faster from the next release
19:26
<
Profpatsch >
Although I feel like nixpkgs has bigger problems than what a 3 times speedup can fix …
19:30
<
infinisil >
Hehe yeah
19:30
<
Profpatsch >
There was this flamegraph setup that gchristensen had
19:31
<
Profpatsch >
Ah, nix_count_calls
19:33
<
Profpatsch >
omg, that’s not printed to stdout
19:44
<
Profpatsch >
infinisil: So, -A hello gives me fold' 3510 calls, foldr 2048 calls
19:45
<
Profpatsch >
mapListToAttrs (after adding it) 2049 calls :)
19:47
<
Profpatsch >
I wonder if we could push this stuff to graphana somehow
20:00
<
MichaelRaskin >
I wonder if that would lead to discovery of a trick which reduces the number of calls but uses something builtin but still expensive-ish so the overall performance still goes down
21:18
<
Profpatsch >
We could implement it in nix
21:47
__monty__ has quit [Quit: leaving]
22:38
<
infinisil >
,profiling
22:38
<
{^_^} >
Use NIX_COUNT_CALLS=1 and/or NIX_SHOW_STATS=1 to profile Nix evaluation
22:38
<
infinisil >
,profiling = Use NIX_COUNT_CALLS=1 and/or NIX_SHOW_STATS=1 and/or --trace-function-calls to profile Nix evaluation
22:38
<
{^_^} >
profiling redefined, was defined as Use NIX_COUNT_CALLS=1 and/or NIX_SHOW_STATS=1 to profile Nix evaluation
22:38
<
infinisil >
Profpatsch: ^
23:03
<
Profpatsch >
yeah, you have to use both if you actually want any COUNT_CALLS output to show