ChanServ changed the topic of #zig to: zig programming language | | be excellent to each other | channel logs:
<Tetralux> You mean toDigit?
<Yardanico> I mean that std formatFloat calls "try parseRepr"
<Tetralux> Not sure
<Tetralux> It only does that once per call.
<Tetralux> But it is a big function
<Tetralux> So maybe.
<Tetralux> But that's not why the non-std parseFloat is slow.
Ichorio has quit [Ping timeout: 264 seconds]
<Tetralux>, mikdusan, kristoff_it.
laaron has quit [Quit: ZNC 1.7.1 -]
laaron has joined #zig
<mikdusan> heh.
<mikdusan> isn't 15ns too fast for string -> f64?
<Tetralux> Nothing is ever too fast ;)
<Tetralux> Also it was actually 12.5 xD
<mikdusan> i'm thinking llvm has totally elided the parseFloat just trying to confirm.
<scientes> mikdusan, it seems reasonable if you had a FPGA implementation
<scientes> but otherwise, yes seems too fast
<mikdusan> ok but parseFloat into a local var never used...
<Tetralux> Would LLVM _really_ elide such a large procedure?
<scientes> especially as you need to use hardware divide
<scientes> well, i think those divides can be switched into multiply actually
<scientes> but not if safety checks are on
<scientes> because you can only do that because of the modulo behavior of divide
<Tetralux> I'll look at the IR.
<Tetralux> Here's the relevant LLVM IR from main.
<Tetralux> Or so I presume.
<Tetralux> If not I can post all of main.
<Tetralux> I'll note that this was compiled with --release-fast
<Tetralux> But for some reason there's still debug stuff?
<Tetralux> Oh yeah
<Tetralux> Forgot to mention
<Tetralux> That IR is when you say `parseFloat(...) catch unreachable`
<Tetralux> The call to parseFloat _is_ in ther.e
<Tetralux> But it prints out that it took 11.8 ns.
<Tetralux> Also the body of parseFloat in the IR is non-trivial.
<Tetralux> All this leads me to conclude that computers are faster than you think they are
* Tetralux grins.
dom96 has quit [Ping timeout: 264 seconds]
<scientes> Tetralux, well in this case the branch predictor would probably do its job very well
<scientes> which makes a big difference
<scientes> also the cache would be very effective
<Tetralux> That's exactly what I was going for so good - I'm glad xD
<scientes> and that speed is the throughput
<scientes> not latency
<scientes> but pipelines are not THAT long
<Tetralux> > throughput not latency -- What exactly do you mean? x)
<scientes> well I don't think it actually matters
<scientes> but if you had a 20 stage pipelines
<scientes> then the "speed" of addition would be 1/20 of a cycle
<scientes> oh wait, 1 cycle
<scientes> ughhhh
<scientes> if you had 20 pipelinable instruction, then you would do all twenty in one cycle
<Tetralux> I wish I knew my CPU internals architectures better now... xD
<scientes> there we go
<Tetralux> Yeah
bastienleonard has quit [Ping timeout: 252 seconds]
<scientes> the craziest thing is out-of-order
<scientes> that is very energy costly however, so most phones have in-order cpus in addition to possibly having out-of-order cpus
<Tetralux> You mean like how you can essentially cook-off a bunch of different adds and they can be executing at the same time
<Tetralux> ?
<scientes> ^^^^video
<scientes> there are so many optimizations its crazy
* Tetralux smiles to himself and opens the video
<Tetralux> Hey - most programmers don't even know what a cache IS, or that the CPU even has a branch predictor, OR that either of those are important for speed, so. xD
<scientes> there are also MANY types of branch prediction
<Tetralux> If you also have a talk on that
<Tetralux> I'll queue that one up too
<Tetralux> xD
<scientes> that talk talks about that
<Tetralux> Oh marvellous.
<scientes> and that is just the public stuff
<scientes> Intel and AMD keep this stuff really secret
* Tetralux nods
laaron- has joined #zig
laaron has quit [Remote host closed the connection]
<daurnimator> Tetralux: I think you're confused on 3158
<daurnimator> Tetralux: the popOrNull returns a ?T. so in your case a ??u64
<Tetralux> That is what I was expecting it to return.
<daurnimator> Tetralux: `orelse` will unwrap one layer, giving you a `?u64`
<Tetralux> Which in my example was null.
<daurnimator> yes.... because you pushed `null`
<Tetralux> Indeed.
<daurnimator> so whats the problem
<Tetralux> Because I was expecting the `orelse unreachable` in the example to _not_ fire.
<Tetralux> I was expecting that to only be checking for whether it managed to pop an element or not.
<daurnimator> I don't think it does
<daurnimator> It does.
<daurnimator> /should
<daurnimator> At least when I tried the example I tripped a compiler bug :P:
<Tetralux> My point was that it was running the orelse statement, even though it found an element, but the fact that the element was _also_ null seemed to cause it to fire.
<Tetralux> Suffice it to say, I did not expect that.
<daurnimator> What made you think it was running the orelse statement?
<Tetralux> Because it hits unreachable.
<Tetralux> And points to that.
<daurnimator> I don't get that. (I get the compiler bug)
<Tetralux> In my own code where I discovered this, I wasn't unreachable.
<Tetralux> it wasnt*
<Tetralux> I never actually ran the example in the issue.
<daurnimator> ...
<daurnimator> <-- try that.... I just get a compiler bug :P
<Tetralux> In my real code, it was `orelse return error.Blah`
<daurnimator> if I change the unreachable to that an error I get the same compiler issue
<Tetralux> I do NOT get a compiler bug with that example.
<Tetralux> I get this:
<Tetralux> If I return an error instead of unreachable, it returns the error instead, just fine.
<daurnimator> Tetralux: running my exact code? I've just tried 4 different similar things and they all hit the same compiler bug
<Tetralux> Yep
<Tetralux> Straight cutnpaste.
<Tetralux> I'm on latest master.
<daurnimator> so am I
<Tetralux> NyatzAxfLNHHkgaz3fLyOMF-x7n2mWbC8ImSoaVAij6lz9lW0YV1TdFOkkD35DCC
<Tetralux> (zig id)
<daurnimator> I'm on IPfzZcvAwpHbi7_u7GmYelMlPukqcgichRJzJCn32UopgQpGji1fR21Ka3siDnSH. But I think you're on windows vs I'm on linux
<daurnimator> So the zig ids are expected to mismatch
<Tetralux> This is true.
<Tetralux> I am on Win
<Tetralux> I have a linux box.
<Tetralux> One mo.
<Tetralux> Nope.
<Tetralux> Also fine.
<Tetralux> Ubuntu 18.04.1
* daurnimator tries with binaries from zig website instead of self-compiled
<Tetralux> zig id = NyatzAxfLNHHkgaz3fLyOMF-x7n2mWbC8ImSoaVAij6lz9lW0YV1TdFOkkD35DCC
<daurnimator> okay. using the official binaries I hit the unreachable
<Tetralux> Maybe time to remake your build directory :p
<Tetralux> Also
<Tetralux> My pastebuffer screwed up
<Tetralux> The second zig id I meant to paste was this one:
<Tetralux> IlodXIZPaAgWA-9f_TUco_EeoXCzn0m2_8BRAF99lS9SR5iubRH3HDDROT_8YcaF
<Tetralux> That's my Ubuntu id.
<daurnimator> Tetralux: the ids aren't super useful i think
<Tetralux> Yeah I'm getting that impression too xD
<daurnimator> I get the hunch that my broken LLVM module error might track down your issue
<Tetralux> Oh?
<daurnimator> Tetralux: inlining things to `const maybe_value = ((??u64)(if (list.len == 0) null else list.pop())) orelse return error.Foo;` doesn't exhibit the issue any more
<daurnimator> so I think there's something going wrong with the LLVM IR genereated for the actual function popOrNull: locally I hit that broken module assertion; while you might be falling through to another case.
<Tetralux> My instinct was that something's probably not checking for if the element is null or not and is just unwrapping all the optionals instead of just the top one.
<Tetralux> But yes
<Tetralux> That's very possible.
<Tetralux> That sounded more dismissive than I intended it xD
<Tetralux> You're thought is probably more likely - it strikes me as kinda hard to accidentally unwrap multiple times - but maybe LLVM's doing it.
<Tetralux> Your*
return0e has quit [Read error: Connection reset by peer]
return0e has joined #zig
<mikdusan> fyi i always got that llvm error when first seeing 3158
<mikdusan> and the error speaks pretty loud. there's a mismatch between 2 types: *?u64 and *??u64 .
<Tetralux> That's true.
<daurnimator> interesting; inlining .pop into .popOrNull fixes the issue.
<daurnimator> So it's maybe something to do with tail calls?
THFKA4 has quit [Quit: WeeChat 2.4]
laaron- has quit [Quit: ZNC 1.7.1 -]
laaron has joined #zig
<andrewrk> `zig id` is for the caching system. it includes e.g. the system's libc. `zig version` is what you want to compare versions with other people
<stratact> andrewrk: I'm interested in getting the "get all the tests passing for freebsd" task completed. How do I activate the tests in my zig git clone?
<stratact> Gotcha thanks
<andrewrk> I recommend to start with behavior tests only. then std lib tests. then the whole test suite with -Dskip-release. Then run without -Dskip-release overnight
THFKA4 has joined #zig
<stratact> I'll keep note of that
waleee-cl has quit [Quit: Connection closed for inactivity]
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 245 seconds]
curtisf has joined #zig
kristoff_it has joined #zig
<andrewrk> mikdusan, it makes sense right? if you put `catch unreachable` at the callsite, you're asserting that there will not be an error. So the optimizer is then free to delete all the code that handles possible errors
<andrewrk> this is why it's a very bad idea to `catch unreachable` in non-safe build modes unless it's actually impossible for an error to occur
kristoff_it has quit [Ping timeout: 245 seconds]
laaron has quit [Remote host closed the connection]
<Tetralux> How can you check if a error union is a non-error without try or catch?
<Tetralux> Or can you not?
<curtisf> I'm actually curious about the above too, I'm trying to work around
<Tetralux> Like, var maybe = f(); if (maybe) |value| { do something with non-error }
<Tetralux> Then you presumably have an else there too.
<Tetralux> Huh... I thought I'd tried that ages ago and it not work.
<Tetralux> I don't remember if it prompted me to put an else there or not.
<Tetralux> I'm gonna guess not
<andrewrk> the examples in the lang ref are tested with the main test suite of zig
<Tetralux> In which case, no wonder I didn't think of putting one there.
<Tetralux> andrewrk: Ah.
<Tetralux> Makes sense.
laaron has joined #zig
<daurnimator> Hopefully the extra sample I added to 3158 helps
<stratact> "Created /usr/home/stratact/Projects/Zig/zig/zig-cache/o/FuM4J9ikyu4oowxPyNH-fxxl2x1MOjmWAopJNS5dff6OIxksqFcdvVWyaQXN5lXh/test but skipping execution because it is non-native." ... 😑
laaron has quit [Remote host closed the connection]
<andrewrk> is this unexpected?
<stratact> Well I got this type of message 15+ more times, without any clues what how the test failed. So it sounds like I need to work on the systems headers task.
<Tetralux> I got those messages quite a lot when running stdlib tests.
<Tetralux> Believe me
<Tetralux> It's better than when it prints "No tests to run" 15 times.
laaron has joined #zig
<Tetralux> I had some problems using filters to only run the tests I was trying to audit as well - never figured out what that was.
<Tetralux> But yes - it'll mention non-native tests a bunch before it gets to actually running interesting things.
<Tetralux> It didn't seem to stop me then.
* Tetralux shrugs.
<andrewrk> stratact, if you run `zig build test` then these messages are expected
<andrewrk> once freebsd is passing all tests, it should be added to this list
<andrewrk> which means even running `zig build test` on e.g. windows, will at least build the tests for freebsd
<andrewrk> even though it cannot run them
<stratact> Gotcha. Thank you guys. I guess I'm learning the ropes to how things are done in Zig and what to expect
<Tetralux> o7
chemist69 has quit [Ping timeout: 276 seconds]
chemist69 has joined #zig
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 245 seconds]
<stratact> Oh yay, I fixed a test
_whitelogger has joined #zig
shritesh has joined #zig
<shritesh> Is Zig complete as a programming language?
<daurnimator> andrewrk: I'm looking at some mild refactoring of the build system.... but encountering some design questions. you available to answer some questions?
<daurnimator> shritesh: well first off, a comptime_int doesn't have a defined memory layout; so the exact example as given doesn't make sense.
<shritesh> So not yet a complete programming language :D
<shritesh> (Sorry I was just curious if we had something like that)
<daurnimator> actually I guess we do defined bit operators on comptime ints..... so maybe it does make sense as a question
<stratact> Tetralux: could you help me out? I'm trying to translate this C function parameter into Zig: void *(*start_routine)(void *)
<stratact> Is it a function pointer?
shritesh has quit [Quit: Leaving...]
<daurnimator> stratact: yes. that's a function pointer to a function that takes a pointer and returns a pointer
<daurnimator> hrm. size of packed structs still has issues :(
<stratact> *fn(*c_void) *c_void ?
<daurnimator> stratact: I think so
<daurnimator> stratact: though you don't really have the `*` at the front in zig IIRC
<daurnimator> stratact: so: `const start_routine = fn(*c_void) *c_void;`
<stratact> I see, thank you :)
a_chou has joined #zig
curtisf has quit [Remote host closed the connection]
_whitelogger has joined #zig
a_chou1 has joined #zig
laaron has joined #zig
a_chou has quit [Ping timeout: 250 seconds]
a_chou1 is now known as a_chou
laaron has quit [Quit: ZNC 1.7.1 -]
laaron has joined #zig
<shachaf> Hmm, is the plan to depend on LLVM forever or to have an alternative backend at one point?
laaron has quit [Remote host closed the connection]
laaron has joined #zig
a_chou has quit [Quit: a_chou]
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 268 seconds]
<gonz_> shachaf: I think at some point the idea of having another backend (gcc, I guess?) became a thing. I don't know that there's an actual plan set up for it, though.
laaron has quit [Remote host closed the connection]
laaron has joined #zig
kristoff_it has joined #zig
laaron has quit [Remote host closed the connection]
laaron has joined #zig
<Yardanico> Yeah, if there are plans to add another backend, I hope it will be C since that will help with portability of Zig programs to less known OSes and architectures
kristoff_it has quit [Ping timeout: 245 seconds]
<shachaf> What about a native code generator?
<Yardanico> I think that's quite hard and it doesn't have a lot of benefits
<Yardanico> But I think Zig should first become fully self-hosted, only then we should think about other backends :)
<Yardanico> And for a language with multiple backends you can look at Nim. It has C/C++/Obj C/JS backends (although the C one is the default), and there's a LLVM backend developed by a single guy (it's not official and not everything works though)
<Yardanico> But Nim stdlib is highly dependent on the C library, buy that's not the case with Zig
<Sahnvour> the motivation for other backends is mainly to have one for debug builds that is seriously faster than LLVM, for now
<Sahnvour> but afaik nothing's really planned yet
dom96 has joined #zig
mahmudov has quit [Ping timeout: 265 seconds]
laaron has quit [Remote host closed the connection]
laaron has joined #zig
mahmudov has joined #zig
laaron has quit [Remote host closed the connection]
laaron has joined #zig
laaron has quit [Remote host closed the connection]
laaron has joined #zig
<Snektron> Its really hard to make a compiler backend, what with the optimization and all
<Snektron> Even if every developer who ever did something related to Zig worked together, i'd seriously doubt they would be able to produce anything thats better in terms of code generation
<shachaf> Better in what way?
<Snektron> That would be able to produce a more efficient binary
<shachaf> I'm sure you could make something that runs more quickly than LLVM, or that gives you more control over things like memory layout.
<shachaf> It probably wouldn't easily be better at compiling the ridiculous code that C++ templates generate, but that's also not nearly as relevant.
<Snektron> Thats compiler frontend
<mikdusan> Snektron: the debug "faster" backend meaning it compiles faster, not produces more optimized code
<shachaf> Stack layout?
<Snektron> Templates are all instantiated before they are passed to LLVM
<Snektron> mikdusan: yes for debug builds its a different story of course
<shachaf> Yes, and they generate terrible code that you need a fancy optimizer to have a hope of turning into efficient code.
<Snektron> You need that fancy optimizer anyway
<Snektron> Templates only generate terrible code when you use them terribly
<Snektron> Its just AST level substitution so it would make no difference if you made the same template instantiation by copy pasting
<mikdusan> except copy-pasting is a million times more readable
<shachaf> "X is only bad when you use it terribly" isn't an excuse when most people "use it terribly".
<Snektron> If you write templates in GNU-style yes
<Snektron> Or if you let me write templates, then you also can't read them
<Snektron> shacaf: isn't that basiacally the anthem of c++?
<mikdusan> how many years did it take compiler vendors to _improve_ template errors? 20?
<Snektron> I woulnd't know, i avoid old c++ compilers
<shachaf> I'm not sure what you're getting at now.
<Snektron> I don't think c++ templates are terrible or unreadablr
<shachaf> OK.
<gonz_> I love compile time code generation and I can't deny that there's something I love about templates, but empirically they seem to cause problems in practice.
<gonz_> I think comptime interface structs in Zig (sort of like first class modules in something like OCaml) are probably better in practice.
<gonz_> They compile down to fast calls, make it obvious what's being passed in, the code is explicit at every step about what it's dealing with.
<Snektron> Thats what attracted me to Zig in the first place
<Sahnvour> Snektron: yes, by "faster debug builds" I meant faster compiling, as for now even with an unoptimized zig compiler, LLVM backedn is taking most of the time
knebulae has quit [Read error: Connection reset by peer]
<stratact> This docgen test is driving me nuts. I wonder if it's a bug with the linker?
<daurnimator> I believe the idea is that zig should be able to use any backend that is sensible. e.g. generate SPIR-V; also generating GIMPLE (gcc)
<daurnimator> You have projects like the linux kernel that are very hesitant to become dependent on LLVM as a project
<daurnimator> From my talks with kernel devs; lack of GCC support is one of the largest blockers to actually having kernel code in zig (aside from stability of the language)
<Sahnvour> with good reasons
<Sahnvour> zig also would be safer if not tied to a single backend
<daurnimator> yes. but also would mean that its slower to add any given Zig feature
<daurnimator> but long term (say 2 years); I would totally expect some zig community member to start upstreaming a GCC frontend
<daurnimator> Yardanico: in terms of priorities.... andrew's concentration is the main thing to ration IMO. If we have some experienced GCC developer turn up, I would be encouraging them to work on a GCC frontend/zig backend
<Yardanico> daurnimator: yeah, I know that andrew is working hard on Zig :)
mgld has quit [Quit: Connection closed for inactivity]
<gonz_> tgschultz or anyone else: What's the current comptime interface suggestion(s)? Is anyone looking like they're considering that actual comptime interface structs with function pointers is a perfectly good solution that we already have right now? All I see is what amounts to overengineering.
<gonz_> Surely the null hypothesis here should be "You don't need to do anything but mark an interface struct parameter as comptime and refer to the functions/contents inside of it and it'll be sorted".
<daurnimator> gonz_: you might want to look at some of bgiannan's examples: they show the need for some sort of comptime interfaces
<gonz_> My point is we already *have* some sort of comptime interface and it's a struct with pointers. Is the argument of "I don't want to pass a struct to every call" what we have against this?
<daurnimator> gonz_: I don't suppose you have history of the channel to find bgiannan's links?
<gonz_> And sure, I'll be happy to change my mind but given how first class modules and functors work in OCaml I'm inclined to not really believe it's needed.
<gonz_> We can take comptime structs with function pointers as arguments, we can return them from functions. That serves all the comptime interface needs I'll have.
<Yardanico> daurnimator: I use quassel so I have logs since sept. 4
<gonz_> Making these implicit serves no real purpose other than saving on typing and making it less clear what's being passed in.
<gonz_> And in most languages with this functionality it also makes compile times much slower.
<daurnimator> Yardanico: there's also the log link in the /title
<gonz_> Haskell has very ergonomic support for type constraints like these and has to search the entire function space to find interface candidates.
<gonz_> It's super slow. Rust is the same.
<gonz_> (Slow at compile-time, that is)
<gonz_> Moreover it just doesn't really provide an upside other than "Yeah, I don't have to type as much". Arguably, though, it's clearer to have the interface explicitly passed in. You can save the interface in a value and just refer to it when you pass it in.
<daurnimator> gonz_: uh, grabbing a seemingly relayed bgiann link:
<gonz_> This isn't really what I'm talking about
<gonz_> Hang on, I'll push some code I have to test this out
<daurnimator> gonz_: ?
<daurnimator> uh; shit same link
<daurnimator> ?
<daurnimator> gonz_: reading his examples I learnt about the deficiency in zig as I ran out of options
<gonz_> I don't think these accomplish the same thing, though. He's trying to solve something like inheritance, or trying to model subtyping, no...?'
<gonz_> I'm trying to solve "Which functions should this thing run?"
<daurnimator> gonz_: how is subtyping difference to inheritence?
<gonz_> It's a much less complicated question and what we have right now solves it completely
<gonz_> I just said they were basically the same thing
<gonz_> And also explicitly that that's *not* what I'm proposing to solve
<daurnimator> Isn't it the same question of "comptime interfaces" though?
<gonz_> What I was questioning before was that it seems "comptime interfaces" to people means more, when it ought not to.
<gonz_> People are involving new keywords, complicated casting machinery, etc., when we basically already have OCaml's facilities and those are provably good.
<gonz_> It's a clear, well performing, readable, maintainable pattern and somehow we "need" more?
<gonz_> You can also remove the comptime keyword on it and determine the interface at runtime
laaron has quit [Remote host closed the connection]
<gonz_> And yes, like OCaml functors you can generate these interfaces as well, which, like when passed in are specialized and correct by construction.
<gonz_> The one caveat being error sets have to be explicit
<mq32> gonz_: i don' think explicit error sets are a problem
laaron has joined #zig
<daurnimator> mq32: they are for e.g. InStream.
<daurnimator> mq32: there is an open "interface" problem is that InStream has to be parametized by error set
<mq32> hm
<mq32> i'm trying something right now
<mq32> can i have "pointer to unknown" in zig?
<daurnimator> mq32: *c_void ?
laaron has quit [Quit: ZNC 1.7.1 -]
laaron has joined #zig
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 245 seconds]
Ichorio has joined #zig
<Snektron> can i pass commands to my program via zig build run with
<Snektron> like how i can do `cargo run -- my-argument`
laaron has quit [Remote host closed the connection]
kristoff_it has joined #zig
laaron has joined #zig
<gonz_> mq32: I don't think it's a particularly big problem either, but it's there.
<Yardanico> SimonNa: zig build run --argument ?
<Yardanico> ah nvm, you're right, that doesn't really work :D
<mq32> gonz_: i don't know if i fully got you, but your argument was "zig doesn't need builtin interface stuff", right?
kristoff_it has quit [Ping timeout: 268 seconds]
<gonz_> mq32: Passing explicit interfaces should be enough, yes, is my point.
<gonz_> I don't see a good argument against it, given that it doesn't need any new constructs, no one needs to learn more than what's already there and it's obvious what's going on.
<gonz_> It compiles down to good code, is hard to misuse, etc.
<mq32> hm
<mq32> so i write my vtables by hand now :P
<gonz_> You take in functions that need to be known at compile-time and use them in the most obvious way.
<gonz_> It also degrades into a runtime requirement pretty gracefully, I'd suspect
<gonz_> But yes, what something like Haskell does automatically for you, you do yourself.
<mq32> hm. i'm still a huge fan of #2938
<mq32> it's still explicit, but it reduced the amount of code i have to repeat
<gonz_> It compiles fast since everything is known at compile-time and since this gels so well with what's already there in zig, specialization of the functions, for speed, is already done because of the fact that you're being explicit. In Haskell, the compiler passes a vtable, literally, at compile time, which is then inlined.
<gonz_> It spends time finding the actual implementation (because it searches globally) and then time trying to actually make it good.
<mq32> i'm with you that implicit interfaces aren't the way to go for fast comptile times (and i don't like them that much anyways)
laaron has quit [Quit: ZNC 1.7.1 -]
<gonz_> It wouldn't be the worst thing in the world to have some kind of interface idea, but I think people are making the null hypothesis more complicated that it ought to be.
<gonz_> When it really is just a struct of functions passed explicitly to a call that's interested in having a certain interface to use.
<mq32> what is good about making some explicit interface declarations in a struct:
<mq32> you SEE what interfaces the struct implements
<mq32> you don't have to do the search-thing by hand (which is way slower than with a compiler :P)
<gonz_> I love Haskell and I wouldn't really change type classes in any way, *in Haskell*. But OCaml has the right idea about explicitness and fast compile times. They've also been flailing around trying to implement "modular implicits", which is a roundabout way of getting a more convenient way of doing the same thing.
<gonz_> When the real value is in having it be obvious which implementation is going to be used at the callsite.
laaron has joined #zig
<gonz_> I'm open to the idea that this will all turn out super well with explicit support for some kind of interface concept, but I wouldn't be disappointed if zig just settled on exactly these explicit interfaces being passed.
<mq32> do you have me a pointer where i can lookup ocaml interface examples?
<Yardanico> seems useful (allows to search for stdlib functions from one .html generated file)
<mq32> that looks useful!
<Yardanico> also it gets comments for stdlib functions, but most of them don't have these, so it's almost empty
<Yardanico> example of generated html - (be careful, it's a 1.1mb html)
<gonz_> mq32: I guess the most obvious place to point to is Real World OCaml, but I'm not enthused about the examples used there:
<gonz_> A functor can be regarded as a function that takes a module and returns a module, so we could have the same thing in zig, just returning a set of functions from a struct of interfaces.
<gonz_> We use functors in a couple of projects at work to ensure that something supplies all functions to fulfill some kind of interface, and then we generate a set of functions from that, that they can use.
<mq32> hm
<mq32> i have never seen any ocaml code
<mq32> is module similar to module in other languages?
<gonz_> As an example we have a `CompanyNameApp` functor that requires that your module has a `phoenix_handlers` value in it that describes how your app deals with incoming messages, etc.
<gonz_> A module in OCaml is a first class value, so we would have it be a struct in zig
laaron has quit [Remote host closed the connection]
<mq32> what function has a "module" in ocaml? storage? execution? object? class? value? :D
<gonz_> The module can be inspected, the components of it can be used piecemeal and you can pattern match on modules as well as pass them inline.
<gonz_> Collection of types and functions
<mq32> hm
<mq32> i don't understand a single piece of code on that page :D
<gonz_> Did you see my example before with the clustering interface?
<mq32> probably not
<mq32> ah that
<mq32> yeah i've seen that
<gonz_> First link points to the specification of the interface. In the type signature of `kmeans` you can see that it takes one of these interfaces and has to know everything at compile time.
<gonz_> Imagine now that you take a function that takes the interface, but also spits out a set of functions.
<gonz_> That's a functor.
<gonz_> You can then bind the result of calling that to a value, access the things it generated or pass to functions, etc.
<gonz_> Effectively, you've generated what can be compared to a "module", a set of values and functions.
<mq32> ah
<gonz_> For most intents and purposes these are the same and practically speaking we've used this exact pattern in TypeScript to generate type safe specialized functions based on interfaces passed in.
<gonz_> We pass an object with function implementations in and we get an object out with some functions, specialized to the interface we passed in.
laaron has joined #zig
<mq32> so you propose instead of kmeans.ClusteringInterface(Point2){ … } just call a MakeClustingerInterface(Point2) ?
<mq32> and that returns the struct prefilled?
<gonz_> Yes, that could be one way to design it and we use that in our TS code.
knebulae has joined #zig
<gonz_> Idiomatically in OCaml you'd have a `Make` function (functor) in the `ClusteringInterface` module that created a ready-made set of functions for you to use.
laaron has quit [Client Quit]
<mq32> i think we had a smaller wording conflict right now :D
<gonz_> Yeah, functor has its roots in mathematics and well, it's persistent...
<mq32> in my world functor is the "function object used to pass function pointers along with its state
<mq32> "
<gonz_> I don't particularly mind this kind of language, but for practical purposes when describing the concept I prefer to state it in terms that we already have at hand.
<mq32> but if i pack the Make function into ClusteringInterface, the module probably has to know *all* possible implementations
<gonz_> What do you mean?
<mq32> ClusteringInterface.Make(Point2)
<mq32> i understood that it would be similar to this ^
<gonz_> You would pass a set of functions to `Make` to get a set of functions out.
<mq32> ah, hm
<gonz_> Module in, module out.
<gonz_> The module you get out is specialized to `Point2`
<gonz_> So imagine you have a `Map`. You pass a set of functions for everything that's needed for a `Map` type into `Map.Make` and get ready-made specialized functions for interacting with a map conforming to the interface you passed in.
<mq32> so just usual generics :P
<gonz_> So you would have a function to hash the thing in the interface, perhaps.
<gonz_> I think the point here isn't really any one example of thins
<gonz_> but rather that it's a very useful pattern and I think the null hypothesis should be exactly that
<mq32> but if i understood you correctly, we do that all the time already in zig
<mq32> ArrayList for example
<gonz_> `ArrayList` takes only a type, as far as I know. But you are right in that it's the same level of obviousness; types and values in, create a ready-made thing from those.
laaron has joined #zig
<gonz_> It seems to me that people have blinders on for the natural extension of that simplicity, so they invent new keywords and obfuscations around it.
<gonz_> `HashMap` is a better example where instead of a struct it's just taking everything parameter by parameter.
<gonz_> But yes, it's an illustration of it, as far as I can see.
<mq32> yeah, but imho it's not the use case we need interfaces for in zig
<mq32> because this method won't work as soon as i want to store a list of interfaces
<mq32> like "everything printable into this list"
<mq32> because then i need at least two pointers
<mq32> one for the function and one for the object itself
<gonz_> I see what you're saying, but I'm not sure it makes sense to me in practise
<gonz_> My main worry is that something more is added and it sucks but everyone is using it and I'll just have to ban it in my stuff and avoid using everyone elses stuff.
<gonz_> And suddenly it's just like Haskell, C++, et al where every dependency should have a "cost" entry in a database for runtime & compiletime.
<gonz_> Or maybe more topical; Rust.
<mq32> gonz_, simple example is games:
mahmudov has quit [Ping timeout: 245 seconds]
<mq32> imagine some kind of interface "Actor" that has an inventory
<mq32> or better, just make the interface Inventory
<mq32> now you want to display inventory UI
<mq32> you can now use your approach which means we get one inventory implementation per inventory type we have in the game
<mq32> </>
<mq32> forget that
<mq32> i'm thinking of a better example, my head is too full right now :D
<mq32> brb
mahmudov has joined #zig
laaron has quit [Remote host closed the connection]
laaron has joined #zig
<Tetralux> By making the interface struct comptime, does calling the fns in the struct become static calls at runtime?
<Tetralux> gonz_
kristoff_it has joined #zig
<gonz_> Tetralux: Yes
<gonz_> Same as calling any other function
<gonz_> I checked the assembly
<Tetralux> Sigh. I still haven't quite figured out the intutition for that it seems.
<gonz_> Specifically `e8 ...`
<gonz_> call near, relative
<Tetralux> My usecase is that I'd be storing the interface as a struct field
<Tetralux> And using it to repeatedly call one of it's fns.
<gonz_> Relaxing the requirement for comptime does change the assembly as well
<Tetralux> If the interface struct is comptime, then field must also be comptime
<Tetralux> I presume
<gonz_> To `ff ...`
<gonz_> I assume so, yes
<Tetralux> But then I thought I can't call it from non-comptime member functions.
kristoff_it has quit [Ping timeout: 258 seconds]
<gonz_> I heartily recommend this pattern as a baseline for "How do I use something with many different things". I have to confess to not seeing why I'd want a heterogenous list of things and not instead a list of the things those things have in common, though.
<gonz_> It's possible that I've just dodged what people are trying to solve.
<gonz_> When things are somewhat heterogenous I'll just push them into a sum type. That's how we handle messages of different types in our apps, for example.
<gonz_> But yeah, if people come up with some obvious, fast and generally good solution, that'll be great.
<mq32> gonz_, your approach with sum types only works for applications, not generic purpose library code
<mq32> i'd have to change your library in order to append custom messages to your message list
<Tetralux> I'll also note that mq32's example requires the library author to apply the interface.
<gonz_> mq32: We have general tools that do exactly that, though. We have functors that require you to have a `message` type. What that message type actually contains is up to you, but it's needed for certain interface functions.
<gonz_> So no, you don't have to change the library code.
<gonz_> We have 3 different apps conforming to our `CompanyNameApp` and they all have different message types. We require in the `CompanyNameApp.Make` functor that you have a message type and that it's used in certain other parts of the interface so we can guarantee a well working ready-made module for you.
<Snektron> i cant read a slice into an array? lame
<Tetralux> Snektron: Slice the array and use mem.copy.
<Tetralux> gonz_: The usecase I had was a simple one. I have a struct that takes a Reader and stores it into a field for later use. A Reader is just a read([]u8) !void; and readByte() !u8;
<gonz_> This extends also to the state of our apps; we require that you have a `state` type, but we don't mandate what's inside of it, since app state is different from app to app. We then require that you have functions that take the app state, a message type and give a new app state, etc.
<Tetralux> I wanted to allow a user of my library to pass an ArrayList, a slice, or something already with read/readByte.
<Tetralux> But found it very awkward to map the Reader's read call to the array.
<gonz_> Tetralux: In that case the interface can say "I need these functions with these type signatures and I need to know the type" and if there are ready made functions those are the implementations passed in the cases of those types.
<gonz_> As far as I understand, at least
<mq32> gonz_, same question: how does your approach handle "store references to different stuff with a similarity into a list" without known all "different stuff"?
<Tetralux> I didn't want the user to have to specify anything, so I had a user-facing function that took `reader: var`, and then used typeInfo to see if it had read/readByte etc or not.
<Tetralux> But I found myself running into `fn([]u8) !void` does not match `bound fn ...`
<gonz_> mq32: If something is "like a list", does that mean it can be turned into a list? In that case, the interface function can trivially be `turnIntoList(value: T) List`
<gonz_> Though you may have misgivings about the performance implications of that.
<mq32> gonz_, i meant something like
<mq32> List.append<T>(T{});
<mq32> not List<T>.append(T{})
<mq32> so "turnIntolist" is wrong, but "addToList" would be right
<mq32> and i want to access functionality of the stuff stored in my List
<Tetralux> mq32: You mean a list where each node can store a different type?
<gonz_> Like I said before, I don't know why I'd be storing heterogenous things in lists. It's something I've dodged since forever, so I can't relate.
<mq32> UI
<mq32> you want a list of childs per widget and each child is a different widget type
<gonz_> `toUiElement(thing: T) UiElement`
<gonz_> Now they're the same
<gonz_> homogenous list
<mq32> and UiElement is a pointer?
<mq32> because i want to implement custom widgets as a user
<Tetralux> You could do the old trick of taking a *BaseWidget and having an array of *BaseWidget
<mq32> yeah
<Tetralux> And having the first field of each widget type be a BaseWidget, etc etc.
<mq32> but that's just inheritance
<mq32> (also similar to interfaces)
<Tetralux> More or less yeah :p
<gonz_> And your widgets could be turned into a `UiElement`. Maybe the interface specifies `onClick` as a way to customize how your widget behaves, etc. When I was doing DOM manipulation in PureScript I made a `IsNode` type class where you specified a way to turn whatever thing it was into a HTML Node
<gonz_> Which then makes it so that you can have different things but turn them into `Node` when you need to
<mq32> but what does UiElement store?
<gonz_> But yeah, I think modeling inheritance and OOP when you don't have them can turn awkward, no question about it.
<mq32> this type is already defined and i cannot change it
<gonz_> I also don't think it's needed
<Tetralux> gonz_: You mean that each Widget type would have a asBaseType() BaseType?
<mq32> i'm still thinking about writing a UI lib in zig
<Tetralux> And each sub Widget knows how to construct a basetype instance to rep it?
<mq32> but i'm not sure if i want to because of missing inheritance
<gonz_> Tetralux: In the interface struct in that case, yeah, for certain functions, or perhaps as a standalone comptime function pointer.
<gonz_> It depends on the interface of the library.
<gonz_> Like I said, I haven't lived in a certain world where you learn to think in inheritance, so take it with a grain of salt.
<gonz_> I just don't see the point. To be fair, I never did while writing C++ either.
<Tetralux> mq32: You can always use the longer-way around perhaps and have a list of union(enum).
<Tetralux> But then you can't add new widget types without changing the union definition.
<mq32> Tetralux, also only works if all widget types are known at declaration time
<gonz_> Your union can be parameterized on the type.
<mq32> you mean on a full list of types
<mq32> like
<mq32> CustomWidget1, CustomWidget2, CustomWidget3
<gonz_> `pub fn Widget(T) type { ... }`
<mq32> that's not possible right now
<Tetralux> I think that the interface way is the simplest way to go then.
<Tetralux> Store a list of interface ptrs.
<Tetralux> And allocate the widgets seperately.
<gonz_> `union(enum) { CustomWidget: T }`
<mq32> yeah that would be my way now as well
<Tetralux> Each widget knows how to construct an interface instance for itself.
<Tetralux> gonz_: Only works at decltime and have to change the definition of the union to add more - but the one adding more might be a library user.
<gonz_> Tetralux: They can add things to `T` without changing anything.
<mq32> gonz_, expanding the enum probably won't work except for some comptime loop stuff
<Tetralux> gonz_: How?
<gonz_> The union doesn't need to change at all for them to add things to `T`
<Tetralux> Is T a struct that they provide?
<gonz_> Yes
<Tetralux> How does it get into the union?
<gonz_> Or well, anything
<Tetralux> Is the union returned from a fn or something?
<gonz_> Yes.
<gonz_> Like any generic
<mq32> hm
<mq32> i don't like the union way at all for extensibility
<Tetralux> Yeah - I've had trouble with that too.
<mq32> it will make a horrible, unmaintainable mess of code
<gonz_> So you can have library offered things in that enum, but also `CustomWidget` that contains whatever type you want to extend with.
<Tetralux> But more from just a awkwardness perspectively.
<mq32> and CustomWidget is just a dispatcher to widgets from, like, 10 different widget libraries
<mq32> and one of my own extensions :D
<Tetralux> It's like the extension type in MsgPack.
<gonz_> The apps that I have that are based on sum & product types + basic interface shuffling are more maintainable than anything else I've seen.
<Tetralux> You have several primitive types - anything else? Put it as an extension type.
<Tetralux> I didn't do CS so I don't know what any of that means xD
<gonz_> Like I said, I don't think in inheritance and things, so I think it's a matter of perspective.
<gonz_> Tetralux: Sum types = tagged unions, product types = records/structs
<mq32> gonz_, inheritance is quite comfortable for a lot of stuff that *actually* inherits
<mq32> UI Widgets are probably the perfect example
<gonz_> Yeah, that's what they usually say.
* Tetralux smiles and shakes his head; wonders why people can't just say the obvious things. xD
<mq32> as some widgets are really similar to each other, but extend only a portion of the code
<gonz_> I just have been convinced over time that there isn't really anything that needs inheritance or is better served by it.
<fengb> Are we discussing theoreticals?
<gonz_> I used to think there was, while still not really getting it. I went full OOP in C++ way back and then just fizzled out because I was just flailing around.
<Tetralux> I think the problem has - and always will be - that talking about these things doesn't actually help - you have to see a working system that makes good use of it.
<mq32> no, fundamentals! religious beliefs! this is the holy war! *laugh*
* Tetralux grins
<gonz_> I'm not trying to be dogmatic about it. I genuinely don't think it's useful.
<fengb> Apple Cocoa has limited inheritance but the userland should almost never use it
<fengb> It has other (arguably better) ways of extending functionality
<gonz_> And let's not frame this as the tyranny of non-OOP; it's the most popular paradigm by far. OOP is doing well, let's not baby it.
<Tetralux> > let's not baby it +1
<fengb> React also is starting to ignore inheritance. I find the two to be much easier to understand than inheritance based widget kits
<Tetralux> Does that have anything to do with multiple inheritance or multiple layers of inheritance?
<Tetralux> Because if you're doing inheritance
<Tetralux> I think single-layer is where its at.
<mq32> mixins! :D
<mq32> *aargh*
<gonz_> Single-layer doesn't work for UI, though...?
<gonz_> You kind of have to go full OO, no?
<Tetralux> I might try to compose before going multilayer.
<mq32> single layer *may* work, if done carefully
<mq32> but all widgets share at least some properties
<mq32> (position, style, ...)
<Tetralux> But then my version of ideal inheritance is basically just composition, so.
<Tetralux> That stuff is what'd go in the bottom layer.
<Tetralux> Then all widgets just compose that.
<fengb> Non inheritance you'd have a separate field for that data
<gonz_> I dunno, this seems like something I'll happily try out but then I'd be afraid if I don't like it it's still there any everyone is using it and I'm becoming a code-hermit prematurely.
<fengb> And interface it to something like "getPosition, getStyle"
<Tetralux> fengb: That's my default-preferred way to inherit.
<fengb> That's not inheritance though :P
<Tetralux> It is.... if you can mark the fields as such.
<gonz_> Tetralux: But then the interface functions are just `getThis`, `getThat`, etc., which works beautifully with the comptime interface struct style.
<Tetralux> This is reality in Jai and Odin.
<mq32> i still like the proposal of mikdusan on that
<mq32> (
<mq32> #2938)
<mq32> it's conventient embedding and fieldParentPtr
<fengb> Ah so something like Go embedded structs
<Tetralux> fengb: .. means you can mark the 'supertype' field `using f: BaseType` and then you can use the fields of 'f' as if they were fields of the enclosing struct.
<fengb> supertype... sounds like prototype inheritance now
<Tetralux> I'm only calling it supertype for clarity's sake.
<gonz_> But we can already just pass an interface struct that gets these fields :D
<Tetralux> It's literally just an embedded struct.
<gonz_> You already have this :D
<gonz_> You can just sit down and use it, now :D
<Tetralux> gonz_: The one thing you cannot do currently is
<Snektron> I don't think its wise to implement go-style inheritance in Zig
<Snektron> or any really
<Tetralux> (Adds something else to that paste)
<gonz_> Tetralux: I know this example is intentionally minimal, but what's so wrong about having to specify a way to get that thing out of the struct beforehand or having to dot a bit further down into it?
<Tetralux> In that particular case, what you're suggesting would simple be "takesBase(s.base)"
<Tetralux> The issue is, you want to write the function to be maximally reusable.
<Tetralux> The implicitness of the casting makes that ergonomic.
<fengb> [implicitness]
<gonz_> It takes a base. It's reusable. Give it a base.
<gonz_> If it needs more, give it a comptime struct of functions to work with `Sub` and one of them is a function to get the `Base`.
<Tetralux> It's fragile to breakage though.
<Tetralux> s.x += 1
<Tetralux> s.base.x += 1
<Tetralux> What if you want to rename the field, as the standard example.
<gonz_> Which field?
<Tetralux> base.
<gonz_> Then your function will not compile because the interface isn't compiling.
<gonz_> It'll tell you `Sub` doesn't have a `base` field.
<Tetralux> Which is unnecessary in most cases, nmo?
<Tetralux> You're only using base at all because you have to provide it.
<gonz_> Why? It's the best kind of error: "Your assumption is wrong"
<Tetralux> It's busy work.
<Tetralux> If it was implicit, this isn't even a problem you have to think about at all.
<gonz_> `<leader>en` takes you to the error, you change it to the new field name, bam.
<fengb> Or... get an IDE to refactor that
<gonz_> These are not hard issues.
<Tetralux> fengb: IDEs are overrated.
<Tetralux> gonz_: I value my time. :)
<fengb> Well it solves this problem much more elegantly than polluting the language
<Tetralux> There's literally no need to have to do this.
<Tetralux> Yes, you could just pass base, and mention my_custom_widget.base.x everywhere if you wanted to.
<gonz_> Tetralux: I think this is just a fundamental difference in outlook. We just have spent time in very different areas of programming and I can't really relate to this particular thing in the end.
kristoff_it has joined #zig
<gonz_> This interface could be created in one place and referred to trivially where it's used, which would give you one compile error to care about, that you fix in a second or two.
<gonz_> Above all, it's a compile time error which is the holiest of errors.
<Tetralux> Simply put - you agree this is a good interface - why not make it more ergonomic?
<Tetralux> That's essentially the root of my point.
<fengb> No, having a consistent interface is good. Implicit coercing into other types is not
<Tetralux> You may think it's already fine, and I see your point.
<Tetralux> I just think it could be better.
<Snektron> Tetralux:
<gonz_> I think passing functions to other functions is good and that's probably what I'll do until the end of time. Sometimes the functions are in structs and sometimes I explicitly generate function pointer structs from other function pointer structs.
<Tetralux> fengb: It only happens when passing to a fn that takes the base type.
<Snektron> oh, it fixes itself after i write the parenthesis
<Tetralux> Snektron: ;)
<Tetralux> Snektron: Also pushed a fix for it anyway.
<Snektron> ah, great
<Snektron> thank you
<Tetralux> o7
<Tetralux> The only issue with this kind of inheritance is that you cannot go from Base to Sub.
<Tetralux> So if you need to look at the information from Sub, you need to pass a Sub.
<Tetralux> Unless fieldParentPtr could help.
* Tetralux shrug
mahmudov has quit [Ping timeout: 245 seconds]
<gonz_> Tetralux: Can I interest you in an interface function called `fromBase(b: Base) T`? :D
<gonz_> Passed at the call site, for your (in)convenience
<gonz_> Jokes aside, could you not just pass the actual thing as a parameter to whichever function needs the subtype as well?
<Tetralux> ;D
<Tetralux> I'm struggling to think of counterexamples right now.
<mq32> gonz_, your proposed solutions of "specialize everything" has one problem we haven't talked about yet :P
<mq32> code size
<Tetralux> But the way I'd handle it normally is with fn overloading.
<Tetralux> One that takes Base, and another for any other type that actually does need to do something special.
<fengb> Code size would be bloated regardless
<Tetralux> In Zig, I obv can't do that.
<gonz_> mq32: The interface can be marked non-runtime, which should be able to solve it...? I've yet to confirm that.
<gonz_> non-compiletime*
<mq32> if it would be runtime, it would decrease code size
mahmudov has joined #zig
<fengb> Oh that's what you meant. Ignore me!
<mq32> but even so, if i have a function instance for every T i call, it will increase linearily with every T
<gonz_> mq32: Right. So if you had a function that checked the type to see which interface to return, could this not be dynamic and not bloat code size?
<mq32> nope
<fengb> andrewrk mentioned he wants an interface pattern that could seamlessly transition between comptime and runtime
<mq32> gonz_, you wouldn't require a function then
<gonz_> mq32: For that I'd concede that some kind of runtime polymorphism solution is warranted, I suppose.
<mq32> because it doesn't specialize anything
<mq32> in C you just pass an interface to such functions
<gonz_> Just to refresh my memory, because I never really use it, if I have `var` is that forced to be known at compiletime or I can check it at runtime?
<mq32> (struct with function pointers + void* params)
<mq32> gonz_, everything regarding types is enforced comptime
<fengb> But we can already emulate that with fieldParentPtr
<mq32> yeah
<gonz_> Whichever way you can do runtime checking you could have an interface generated that does exactly that.
<gonz_> No?
<mq32> we cannot do runtime type checking
<mq32> we don't have RTTI, only TI
<mq32> (run-time type information vs type information)
<mq32> zig only has static reflection
<gonz_> Right, so this is not really an issue with passed interfaces so much as an issue with checking at runtime
<gonz_> Because if there was a "check at runtime" interface passed, it'd do just that.
<mq32> dunno. reducing code size would work by predeclaring all interfaces as const objects
<mq32> instead of emitting functions that create this interface
<gonz_> I'm not sure I follow 100%. The interfaces themselves don't actually take up any size or whatever.
<gonz_> It's the functions that they refer to that actually exist.
<gonz_> Reducing code size would be a question of removing the need for different functions being referred to, so checking at runtime in the one function they all use.
<gonz_> 'cause we're talking the tradeoff that Rust highlighted a few weeks back, right? People overuse static polymorphism and code size rockets up.
<gonz_> The passed interfaces don't actually really exist AFAIK, they don't show up when debugging, for example.
mattmurr has quit [Ping timeout: 246 seconds]
<gonz_> They do point to the very specific, specialized functions that you put in them, though, so there's no question that each thing has its own, but whichever way you'd then have runtime polymorphism, an interface could also specify those functions.
<mq32> gonz_: your example code you posted earlier (kmeans)
<mq32> creates one implementation per type used
<gonz_> Yes.
<mq32> so if you use it with Point2, it has size N*1
<mq32> if you now use it also with Point3, you have N*2
<mq32> …
<mq32> and so on
<gonz_> Yes. So we are on the same page.
<mq32> to reduce code size it would require to not be specialized on a type
<mq32> okay, good :)
<gonz_> It's the existence of the specialized functions that is the thing that bloats the code size.
<gonz_> And yes, runtime checking is the solution to bloated code size.
<gonz_> So it's not inherently any issue with passed interfaces.
<gonz_> I'm not saying you wouldn't need some modification, though; I probably would have a function that required a comptime interface and possibly one that didn't.
<mq32> to reduce code size bloat you'd have to remove any type dependencies
<gonz_> But this is the same issue you'd have if you just had a bunch of code. If I wanted to implement K-means clustering for 10 types without passed interfaces I'd have the same amount of code as I do with passed interfaces.
<mq32> so kmeans would be called with "this start pointer, this stride, this function takes two untyped pointers and returns distance"
<mq32> no, you can do that without any interfaces
<mq32> C syntax would be something like
<gonz_> If you had 10 specialized kmeans clustering functions you'd end up with the same amount of code
<mq32> void kmeans(void * elements, size_t elementStride, size_t elementCount, float (*distanceBetween2)(void * a, void * b));
lunamn has joined #zig
<gonz_> `kmeans_point{2,3,4 ...}`
<mq32> now you can pass in any type, without increasing code size
lunamn_ has quit [Ping timeout: 245 seconds]
<gonz_> Right, sure.
<gonz_> Specializing increases code size, which I'm fine with. Having alternatives to specializing isn't something I'm against.
* mq32 has the glasses of an embedded coder
<fengb> Embedded UI?
<mq32> ah.... yes
* gonz_ has the glasses of whatever the other thing is :D
<mq32> at work we have a UI system that has separated widgets
<gonz_> Though I'd like to work with embedded stuff, but that's mostly so that I'll be forced not to over-abstract.
<mq32> each widget consists of a .data and a .rodata part
<mq32> so we don't use too much RAM
lunamn has quit [Ping timeout: 244 seconds]
<mq32> (position, size, callbacks, ...) is .rodata (flash memory) and stuff like (isChecked, text) is .data (RAM)
<gonz_> I know no one in embedded work and I make a killing in backend work so I haven't been sufficiently motivated to get to looking for work in lower level stuff as much.
<gonz_> My last work offer was for Haskell on the backend and I work with Elixir now, so I'm about as far away from embedded as you can get in some sense.
<mq32> hah
<mq32> i'm planning some crazy project right now
<mq32> still not sure if i go with zig, c++ or C
<mq32> but my experiments the last days show that i would probably work around a lot of zig compiler bugs and be blocked in actually getting something done
<andrewrk> nontrivial projects in zig will require participating in the development process to some degree
<mq32> yeah
lunamn has joined #zig
<gonz_> Do it in C++ and rewrite it in zig :D
<gonz_> Write a blog post on HN about how you've seen the light
<mq32> haha
mahmudov has quit [Ping timeout: 245 seconds]
<mq32> first i have to figure out my requirements on the project
<mq32> will be some kind of "new" UI system with some aspects of Web Development and some aspects of, well, other stuff :D
<gonz_> Who was it that had the setup with ALE for `zig build`, by the way?
<gonz_> I need to get me some of that
<gonz_> Don't hoard these sick scripts, whoever it was
lunamn has quit [Ping timeout: 268 seconds]
laaron has quit [Quit: ZNC 1.7.1 -]
laaron has joined #zig
<Snektron> "Cannot store runtime value in type 'comptime_int'"?
kristoff_it has quit [Ping timeout: 268 seconds]
<Snektron> this is on a if (a) 1 else 0 type construction
<fengb> Peer type problem. You need to manually cast one of the literal
<Snektron> i see, thanks
<Tetralux> mq32: Please make it trivial to lay things out.
<Tetralux> I still use .Net whenever I want to make a program with UI _just_ because of how easy making UIs in that is.
<Tetralux> And that's in no small part because of .Anchor.
ntgg has joined #zig
<Tetralux> (It keeps certain edges of a Widget equidistance from that sides' edge.
<Tetralux> s/from that sides' edge/from that sides' window edge.
<Tetralux> If I have to make 20,000 layers widgets just to lay out the window in a sane way... :)
lunamn has joined #zig
<Tetralux> layered*
<Tetralux> Well - it's mostly cuz graphical UI for laying out the UI - but still.
lunamn has quit [Ping timeout: 246 seconds]
lunamn has joined #zig
<gonz_> Do we have a `.seen` command on a bot?
<gonz_> As in you can query a bot about when someone was last seen in the channel.
laaron has quit [Remote host closed the connection]
<gonz_> It was fubd who had the ALE linter, it turns out. :/
<Snektron> I feel like there should be a way to cast a pointer to a slice without a lot of builtin functions
laaron has joined #zig
<nrdmn> sync your portage trees
<Snektron> I doubt that will help
<nrdmn> it's generally a good idea
<Yardanico> 925593
<Yardanico> sorry wrong window
<gonz_> Time in seconds spent compiling GHC
<Yardanico> gonz_: it's actually a GitHub 2FA sms code :D (don't worry, I already used it)
laaron has quit [Remote host closed the connection]
earnestly has joined #zig
laaron has joined #zig
ntgg has quit [Ping timeout: 245 seconds]
Akuli has joined #zig
<stratact> andrewrk: yesterday I managed to fix one test, but I've been having bad luck trying to figure out this one, since it deals with the linker:
<stratact> I think I got most of the tests to past except for docgen
shritesh has joined #zig
shritesh has quit [Quit: Leaving...]
laaron has quit [Remote host closed the connection]
laaron has joined #zig
mattmurr has joined #zig
return0e_ has joined #zig
return0e has quit [Ping timeout: 245 seconds]
<andrewrk> stratact, the zig std lib assumes pthread_attr_setstack is available in libc, but it appears to not be available in FreeBSD. That is surprising, I would like to ask devs about it
<andrewrk> also pthread_create? maybe zig simply needs to add -lpthread to the linker line for FreeBSD
<andrewrk> that's in src/link.cpp
rjtobin has joined #zig
mahmudov has joined #zig
<Snektron> can i be generic about const in Zig?
<Snektron> its annoying to write a get() and getConst()
<Yardanico> are you using it for []const u8?
<Snektron> member function in this case
<Snektron> for example i have this struct which fetches a pointer to another thing
kristoff_it has joined #zig
<andrewrk> Snektron, that's an unsolved problem at the moment
<Snektron> if the struct is declared as const the pointer return should be const of course
<Snektron> andrewrk: i see. I heard about a programming language which allowed to be generic about that, and about errors in a certain way, but i forgot which one it was
kristoff_it has quit [Ping timeout: 258 seconds]
earnestly has quit [Ping timeout: 246 seconds]
<stratact> andrewrk: by linker line, you mean the LinkJob object?
earnestly has joined #zig
<andrewrk> stratact, yes, look at construct_linker_job_elf for example
<stratact> gotcha, thank you
fubd has joined #zig
<andrewrk> stratact, per issue we're going to have a special case in there anyway for freebsd
<fubd> gonz_ here's what i've got for an ALE zig linter
<fubd> it finds build.zig and calls "zig build" but a more general solution would probably not be far from that
fubd has quit [Remote host closed the connection]
<andrewrk> stratact, and you can add specific detection for freebsd (g->zig_target->os == OsFreeBSD) and mess with the linker line there, such as by adding -lpthread
<stratact> Understood, I'll use the FreeBSD detection conditional for the -lpthread append and play around
<scientes> is there a function to check if two types are compatible?
<scientes> or functions
<scientes> oh nvm
<stratact> andrewrk: omg, yay, it worked! :D
<stratact> It feels so good
shritesh has joined #zig
<gonz_> Ahhh, realtime syntax and type checking for zig
<gonz_> (in vim)
<gonz_> Living the dream
<stratact> Once docgen test is completed, I'll do a full test with -Dskip-release and another without it and if all good, I'll make a PR 😌
shritesh has quit [Quit: Leaving...]
Tetralux has quit [Read error: Connection reset by peer]
casaca has quit [Read error: Connection reset by peer]
Tetralux has joined #zig
ntgg has joined #zig
casaca has joined #zig
<scientes> gonz_, really?
<scientes> that requires running zig
<gonz_> Indeed it does. It's actually annoying to have it on text change
<gonz_> so I switched to only save
<scientes> for stage2 we will work on zig's compile performance
ntgg has quit [Ping timeout: 246 seconds]
<gonz_> You can also set a text change delay for it with debounce, AFAIK, so with just some tuning of that, if zig can actually give you realtime results in the future in a reasonably sized project, that'll be pretty sweet.
<gonz_> Though, to be honest, I don't expect this. There are only two languages that do a decent job of this that I've tried and they are OCaml & TypeScript
<scientes> gonz_, well since zig is limited to one thread it isn't annoying if you have bazillions of ram and 2+ cores
<scientes> gonz_, just another side effect of comptime
so has quit [*.net *.split]
Akuli has quit [Quit: Leaving]
so has joined #zig
<Yardanico> gonz_: there's also zig-lsp although atm it mostly has syntax checker (braces, invalid ;, etc)
<Yardanico> imagine coding in zig with real-time autocompletion 😍
<scientes> and real autocompletion
<scientes> instead of that shit that mode editors produce
<scientes> *most
earnestly has quit [Ping timeout: 268 seconds]
<Yardanico> well, I previously used nim, it has an autocompletion tool (nimsuggest), and there's a vscode plugin for it, so it's a real real-time autocompletion
<Yardanico> although it doesn't use language server protocol
earnestly has joined #zig
<gonz_> Currently I run a program called TabNine the checks for patterns in your source code and auto completes them when it sees you typing them.
<gonz_> s/the/that
<Yardanico> wow, that exists? I though there were no alternatives to Kite which wasn't actually working
<Yardanico> gonz_: thanks for suggestion, I'll try it rn
<gonz_> It exists, yeah, and works pretty well. Since it doesn't really rely on any language specific things it can actually pick up patterns for any language, even if you have maybe some dependency in C that you use in zig.
<gonz_> I wouldn't say it's perfect, though.
<gonz_> I'm using it with zig only because there's nothing else.
<Yardanico> well of course, but it's good enough if there's nothing else I guess
<Yardanico> I think TabNine + zig-lsp + vscode right now is the most you can get for Zig
<gonz_> What could be interesting and that I haven't actually explored is to let it loose on big code bases in a language to soak up all the idioms and then you use it for yourself.
<gonz_> And you'll be getting suggestions for common ways to express stuff (maybe).
<gonz_> Like I said, I haven't really checked how well that'd work.
<Yardanico> gonz_: I'll try it right now
<gonz_> I did open up a few Haskell open source projects up at some point and then coded myself and it did have some impact.
<gonz_> But the biggest impact I saw at the time was when I was writing boilerplate DB migration scripts in Elixir and it actually autocompleted entire sections for me.
<Yardanico> damn TabNine deep learning model is 684mb
<gonz_> It could usually guess at what the next thing I was going to write. So it's pretty good for boilerplate stuff.
<Yardanico> and you can actually enable sending your code to their servers for GPU-powered completion (although it's off by default which is nice)
<Yardanico> well, they say they remove it after the query, but who knows :D
<gonz_> Yeah, nah :D
<Yardanico> hm, their binaries actually use musl which is nice
<gonz_> It's a pretty neat project and I hope they do well. I ended up not using it after a while when I first tried it because it clobbered all other auto-completion, but I figured now that with zig I really only have some basic editor word completion anyway.
<Yardanico> I think that if they get enough money they can train their model on the entire GitHub database
<Yardanico> since it already exists in google BigQuery
kristoff_it has joined #zig
<Yardanico> LOL "In recognition of the fact that TabNine could not exist without the Rust ecosystem, TabNine's paid features are always enabled when completing Rust code."
<Sahnvour> you-complete-me + language-specific tools also does a great job
kristoff_it has quit [Ping timeout: 258 seconds]
<Snektron> is it me or does setOutputDir not work anymore?
<Tetralux> I just discovered what I think was the commit that broke the fast parseFloat code I wrote: 42cc4a406bd4d037f4203fa2ebca2853db33c780
<Tetralux> On this commit, 11ns. Next commit forwards: 144ns.
earnestly has quit [Ping timeout: 258 seconds]
<scientes> ughhh, changes like renaming bigint_as_unsigned to bigint_as_u64 are really annoying for maintainers of PRs
<scientes> it means i have to build every patch when i rebase
<Tetralux> At least you're doing it on Linux where building takes 30 seconds.
<Tetralux> On Windows it can take upwards of 2 minutes.
<scientes> well I just rebuild zig0
<scientes> user-mode takes too long
<Yardanico> what is the current state of networking and threading/concurrency in zig?
<scientes> Yardanico, needs to be implemented
<Yardanico> scientes: so no http requests in pure zig (without C libs) for now?
<scientes> I'm pretty sure coroutines got merged
<scientes> so it can now be implemented correctly (and not the lame C way)
<fengb> Yeah async is in, andrewrk is still working on bugs and primitives like event loos, channnels, etc.
return0e_ has quit [Read error: Connection reset by peer]
return0e has joined #zig
<Tetralux> So...................
<Tetralux> Fun story.
<Tetralux> If you comment out std/mem.zig:342, my code runs 13.5 times faster.
<scientes> Tetralux, well yeah, that really should use @memcmp
<scientes> or whatever we call the llvm intrinsic
<scientes> or actually, @bcmp
<Tetralux> This is insanity. Checking if two pointers are equal vs that much speed degredation!
<Tetralux> That doesn't seem right at all.
<scientes> Tetralux, it makes prefect sense
<scientes> thats what happens if the branch predictor doesn't work
<Sahnvour> why would it not work when comparing the pointers, but work when comparing the data ?
<scientes> it doesn't work either times
<Sahnvour> Tetralux: did you identify what slice comparison takes longer in your code ?
<scientes> but failing twice is much worse than failing once
<scientes> also if you sort the data the branch predictor can work better
<scientes> in many cases
<Tetralux> There's only two mem.eqls in the code.
<Tetralux> Both are at the top
<Tetralux> They check for "inf" and "nan"
<scientes> Tetralux, you can't check for nan with mem.eql
<Tetralux> scientes: We're parsing strings; if the strings compare to "inf" or "nan" then it returns the appropriate floating point value.
<scientes> ohhhhhh
<Tetralux> Otherwise it actually parses the string.
<Sahnvour> well obviously in that case, checking for pointer equality is not going to help
<Tetralux> Basically, the ptrs will not ever be equal, because we're comparing a string literal with the given slice.
<scientes> Tetralux, it would be faster if you just checked if the first character is a number
<Sahnvour> but still, I'm a bit puzzled by such a degradation
<Sahnvour> you should compare the generated code
<Tetralux> scientes: Maybe, but it evidentally didn't matter before.
<Tetralux> Sahnvour: Also yes.
<Tetralux> Like - this is the worse kind of footgun, at the very least.
<Tetralux> Futher, I checked godbolt. I cannot find any obvious difference.
<Tetralux> But I suck at using godbolt for diffing machine code.
<Tetralux> They seem to have removed the ability to even bring up the diff.
<Snektron> > That doesn't seem right at all.
<Snektron> Without context because im lazy, this screams `noalias`
<Tetralux> Snektron: Can't use noalias on mem.eql unfortunately, since they could _actually_ be the same, even though my example they would definitely not be.
<Sahnvour> besides, your code seems to be parsing the same float again and again, so I would expect the branch predictor to be just fine in learning that
<scientes> there is no need for noalias on memcmp anyways
<scientes> cause it doesn't change anything
Ichorio has quit [Ping timeout: 264 seconds]
ltriant has joined #zig
<Sahnvour> how up to date is godbolt with trunk zig ?
<scientes> Sahnvour, it builds it often enough
<Sahnvour> cool
<scientes> oh rather
<scientes> it downloads it from
<Sahnvour> that's automated ?
<scientes> yeah
<scientes> ziglang builds every commit
<scientes> its part of the CI
<scientes> CI uploads to
<Tetralux> I just realised that I wasn't actually doing it right when I checked on godbolt before.
<Tetralux> I can't even run my example code in 0.4 because it uses std.time.
<Tetralux> So I can't use godbolt to diff it anyway.
<Tetralux> Also, Zig does not seem to have @memcmp.
<scientes> I had a patch, but I never polished it
<scientes> to do stuff related to that
<Snektron> Tetralux: just copy memcpy
<Snektron> actually, maybe there should a non-overlapping version of memcpy
<Tetralux> know where it is?
<scientes> Snektron, that is called memmove
<Snektron> i mean it should be added
<Snektron> sorry, i meant memcmp
<Sahnvour> Tetralux: first things first, you should benchmark on strings that are not easily known to the compiler, in your example it's able to unroll `parseFloat` based on 4.77777777
<scientes> cool, SIMD PR updated
<scientes> with a new feature
<andrewrk> thanks scientes. I will definitely make an attempt to get that merged before the release
<Tetralux> Sahnvour: I'm pretty sure that's not it.
<Tetralux> But just to be sure I generated a random string of digits.
<Tetralux> If I remove the line, it takes 10ns.
<Sahnvour> it is, take a look at assembly starting at line 757
<Sahnvour> it's basically iterating over your number string (`__unnamed_3`)
<Sahnvour> incrementing the offset with a couple instructions each time
<Tetralux> Yeah - seems unrolled to me.
<Tetralux> But even if I make it use random numbers
<Tetralux> It still only takes 12 ns.
ntgg has joined #zig
<Sahnvour> can you try with the additional pointer comparison, but calling mem.eql as @inlineCall ?
<Tetralux> Hmmm.
<Tetralux> I think using random numbers means you have that pointer comparison and it doesn't slow it down.
<Tetralux> Here's how I'm doing it
<Tetralux> (Bad indentatio)
<Tetralux> indentation*
<Sahnvour> I'd init the prng with current time, to be really sure the optimizer can't see the digits it will generate
<Tetralux> Firstly
<Tetralux> Just tried with time.timestamp as the seed
<Sahnvour> I'm out of time now, but it would be interesting if you can get an assembly comparison with the smallest possible repro
<Tetralux> Still 12ns without the check, and >100 with it.
<Tetralux> I'm gonna try what you suggested with inlining it.
kristoff_it has joined #zig
<Sahnvour> also maybe it chooses to unroll it by seeing it's fixed length, and the actual content of the string doesn't matter that much as long as it's short enough to be worth unrolling
<Tetralux> OOooo
<Tetralux> So
<Tetralux> I realised that I was checking the wrong example
<Tetralux> But
<Tetralux> If I have the check
<Tetralux> And don't use string literals
<Tetralux> (randomly generate)
<Tetralux> Then it's fast.
<Tetralux> But if I do use literals, then it's slow with the mem.eql ptr check.
kristoff_it has quit [Ping timeout: 246 seconds]
<Tetralux> Inlining the call to mem.eql does NOT make it any faster.
<gonz_> Ah, this chat log is fantastic
<Yardanico> how do I actually LINK a .a library? trying to do "const lib = b.addStaticLibrary("libui", null);" and then "exe.linkLibrary(lib);" fails with "libui: linker needs 1 or more objects to link"
<Tetralux> Does it work if you just .addObject("libui.a") ?
<Tetralux> I've never used any of that, but I seem to recall this question coming up before.
<Tetralux> gonz_: XD
<Yardanico> Tetralux: "reached unreachable code"
<Yardanico> "/usr/lib/zig/std/build.zig:1606:15: 0x246729 in (build)"
<gonz_> Isn't `addStaticLibrary` for creating one in your project, from your source?
<Yardanico> gonz_: then what's the one for linking with .a library? :D
<gonz_> I'm looking through `` to see
<Tetralux> Maybe .addObjectFile ?
<Tetralux> (passing the path to the .a)
ntgg has quit [Remote host closed the connection]
<Tetralux> There's also .addLibPath too if that doesn't work :D
<Yardanico> Tetralux: addObjectFile seems to be it
<Tetralux> Okay good
<Tetralux> We really should put all these details somewhere so we don't have to search for it every time.
<Tetralux> Or better yet
<Tetralux> Make it blatantly obvious.
<Yardanico> damn, I managed to run libui controlgallery example from Zig
<Yardanico> although the raw C syntax for using it is far far far from perfect -
<Yardanico> but zig translate-c is very useful anyway
<gonz_> If nothing else it can provide a way to build better ways to interact with a lib
<Yardanico> well yeah
<scientes> does anyone have cannonlake hardware I can test on?
<Yardanico> also, on a good note - zig in release-fast mode is only 16kb (168 vs 152kb) bigger than original controlgallery built in release mode (well they dynamically use GTK libs anyway)
<Yardanico> ah nvm lol, after stripping both binaries zig binary is actually smaller by 4kb
<Snektron> why is @byteOffsetOf giving me invalid values
dbandstra has joined #zig
dbandstra has quit [Client Quit]
<Snektron> ah
<Snektron> packed structs don't work with @byteOffsetOf
<Snektron> sometimes
return0e_ has joined #zig
<Snektron> oh boy
<Snektron> this is a fun one
dbandstra has joined #zig
return0e has quit [Read error: Connection reset by peer]
<Snektron> this is really annoying