<daurnimator>
frmdstryr: basic idea is: a 'scheduler' object 2 linked lists: 'polling' and 'pending'. when a thread wants to wait on something, it puts itself into the polling linked list. When the scheduler wants to do something it pulls off the pending list.
<frmdstryr>
makes sense
<fengb>
andrewrk: I seem to be getting extra crashes with the new `ir-clean-up-vars` branch
<fengb>
Oh it's the probably the same one that's crashing CI. Ignore me!
<daurnimator>
fengb: I don't like that the generator form requires a copy...
<fengb>
Which copy?
lupine has quit [Read error: Connection reset by peer]
lupine has joined #zig
ltriant has joined #zig
ltriant has quit [Client Quit]
kristoff_it has joined #zig
<daurnimator>
fengb: I was looking at your godbolt link
<daurnimator>
==> line 1050
<fengb>
How would you load it directly without a callback?
<fengb>
I need to figure out why it's performing so bad. I have some ideas, but maybe it's just the async spill bleeding everywhere
<daurnimator>
funnily enough, this dilemma is one of the things LinearFifo solves
<fengb>
Because the callback version is probably fully inlined, while LLVM doesn't understand all these suspends
<daurnimator>
==> sometimes you want to copy from e.g. a constant in the .data section; sometimes you want a destination to write to directly because you're generating at runtime
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 258 seconds]
<frmdstryr>
How do I initialize an array of optional types to all null?
<daurnimator>
frmdstryr: `[_]?u8{null} ** N` ?
<frmdstryr>
ah, ok I had the ** inside
<daurnimator>
frmdstryr: you question does scare me though: if its related to a scheduler, you don't want to run out of room or require allocations: that's why you use an intrusive linked list
<frmdstryr>
Didn't get to start on the event loop yet, stil working on getting the hardware timers working
<andrewrk>
fengb, I just now got the behavior tests passing in that branch, and there are still a bunch of std lib test failures. I wouldn't try it yet
<andrewrk>
but it's been easier to debug in this branch, so that's a plus. this should make it a bit more straightforward to fix result location bugs
<lunamn_>
question about sentinel-terminated pointers: how do I proceed to going from [*]T to []T if something like std.mem.len only allows [*:0]T?
<daurnimator>
lunamn_: where did you get the [*]T from?
<daurnimator>
(and how do you know its null terminated?)
marijnfs_ has joined #zig
marijnfs has quit [Ping timeout: 260 seconds]
<lunamn_>
daurnimator: context, libexpat allows callbacks, i wrote them in zig (export fn), and the compatible type for a parameter that is [*c]const u8 in the callback's declaration is ?[*]const u8
<fengb>
Ah cool, I have some major performance problems that I can fiddle with. I think part of it is that suspend is slow :/
<daurnimator>
lunamn_: sounds like your callback should take a `?[*:0]const u8` instead
<lunamn_>
daurnimator: yeah, that was my thought, and well, "expected type 'fn(...[*c]const u8, ...) callconv(.C) void', found 'fn(...?[*:0]const u8...) callconv(.C) void'"
<daurnimator>
lunamn_: I guess you'll need to @ptrCast for now
<andrewrk>
fengb, in theory suspend shouldn't be slow. it's just `return`. but in practice, llvm's optimizations have been over-fitted to C, which does not have async functions
<andrewrk>
as an example llvm doesn't have the ability to remove fields from structs even though it's legal in zig
<fengb>
I’ll do some analysis to figure out where all the instructions are going. It looks pretty foreign to me atm
<andrewrk>
but yeah I can imagine there are patterns where unfortunately llvm does not optimize well
<andrewrk>
hopefully rust community will land some patches to improve it, since they have similar async codegen :)
<andrewrk>
I'd be curious to ask rust devs if they have experienced similar problems trying to get llvm to optimize async functions
<daurnimator>
andrewrk: "ability to remove fields from structs"?
<andrewrk>
fengb, oh! one more thing I thought of. zig uses atomic instructions for `return` in async functions when not using --single-threaded. in the case of using them for std.fmt.format, atomic instructions are not needed. it is related to optimization to avoid using atomic instructions
<andrewrk>
this might be another reason to do generators
<andrewrk>
because since you couldn't do `await` on a generator, zig would know to not use atomic instructions for `return` (or `yield`)
<andrewrk>
hmm doesn't seem to change much in your godbolt example
<andrewrk>
daurnimator, llvm optimizations will never remove unused fields from structs
<andrewrk>
and zig generates async functions with all local variables as a struct
<andrewrk>
so while llvm is able to remove local variables from functions, it is not able to remove local variables from async functions
<lunamn_>
daurnimator: ptrCast did the trick, thank you
<andrewrk>
lunamn_, was there an compile error note attached to that error?
<lunamn_>
andrewrk, well, yes, but it wasn't helpful? it said that the cast wasn't possible, and that destination pointer requires the sentinel, but I stayed confused on what could I do
<andrewrk>
I just wanted to make sure that was there - so yes the compiler is incorrect; it should allow the cast. thanks
<lunamn_>
should I open an issue to keep track of it or?
<andrewrk>
yes please if you would
<lunamn_>
gotcha
<lunamn_>
weird. I'm trying to create a test case that doesn't involve all of libexpat and it's weirdly.. working?
<lunamn_>
nvm, got it
mahmudov has quit [Ping timeout: 258 seconds]
rageoholic has quit [Remote host closed the connection]
doublex has quit [Ping timeout: 260 seconds]
kristoff_it has joined #zig
doublex has joined #zig
kristoff_it has quit [Ping timeout: 260 seconds]
kristoff_it has joined #zig
doublex has quit [Ping timeout: 260 seconds]
dddddd has quit [Remote host closed the connection]
kristoff_it has quit [Ping timeout: 240 seconds]
doublex has joined #zig
kristoff_it has joined #zig
<pixelherodev>
Is `if (a) |unwrapped| { a = null; // do something with unwrapped }` valid?
<pixelherodev>
That is, is the unwrapped value dependent on the wrapped variant?
<pixelherodev>
Ah wait, had the `= null` afterwards because I was fixing up something else before making that switch
<pixelherodev>
daurnimator, thanks!
ur5us has quit [Ping timeout: 260 seconds]
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 260 seconds]
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 268 seconds]
return0e has joined #zig
kristoff_it has joined #zig
kristoff_it has quit [Ping timeout: 268 seconds]
kristoff_it has joined #zig
alexpana has joined #zig
_Vi has quit [Ping timeout: 245 seconds]
kristoff_it has quit [Remote host closed the connection]
alexpana has quit [Ping timeout: 260 seconds]
redj has quit [Ping timeout: 268 seconds]
bheads has quit [Quit: bheads]
bheads has joined #zig
alexpana has joined #zig
alexpana has quit [Ping timeout: 268 seconds]
dddddd has joined #zig
bheads has quit [Quit: bheads]
bheads has joined #zig
return0e has quit [Ping timeout: 265 seconds]
_Vi has joined #zig
frmdstryr has quit [Ping timeout: 245 seconds]
rankao has quit [Remote host closed the connection]
epmills has joined #zig
<epmills>
hey, all!
<mq32>
hey epmills
<epmills>
i know it's early days for http clients but does anyone have experience reading JSON from a REST service?
<epmills>
nothing complicated like oauth just passing a client id and secret and getting bytes back.
<mq32>
i don't think we have a working HTTP client in the language yet
<mq32>
at least not to my knowledge
<mq32>
but daurnimator did something regarding HTTP headers some time ago
<epmills>
thanks, @mq32
<epmills>
i was wondering about: std.net::tcpConnectToAddress(address: Address) !fs.File
<mq32>
that should open a TCP connection
<mq32>
but you can go ahead and start to implement a HTTP client on top of that
<epmills>
cool - i'm gonna give that a shot. really digging zig a ton. many of my pet projects involve reading JSON from an API, parsing and spitting out some result.
<bheads>
if your on windows you could try the winhttp apis
<epmills>
ah, i'm on macos but using an existing lib's an interesting way to go. cheers.
<mq32>
would be cool though to have a zig-only solution for HTTP
<fengb>
That’s on hold until async IO is a bit more robust
<bheads>
I think that is the plan
<fengb>
I’m trying to get async OutStream working and there’s some library improvements but it’s slowly getting there
<bheads>
is that the generator version of streams?
<fengb>
Yeah
<bheads>
nice!!!
<bheads>
is this a formal zig language supported generators or just abusing async for now?
<fengb>
Abusing async. I think andrewrk is coming around to adding it but the userland version isn’t too bad
<fengb>
Unfortunately I perf tested it and it’s noticeably slower. I’m hoping a deeper dive can explain why
epmills has quit [Quit: Leaving...]
epmills has joined #zig
epmills has quit [Remote host closed the connection]
epmills has joined #zig
epmills has quit [Remote host closed the connection]
epmills has joined #zig
epmills has quit [Remote host closed the connection]
<betawaffle>
is there any plan to expose the result location of a function inside the function body? or more specifically, the ability to detect if the result location is void/ignored or not?
<mikdusan>
on the last part I don't recall seeing any PR for "detect if result loc is void/ignored" in fn body
bheads_ has joined #zig
<betawaffle>
i guess the question becomes: is it even possible to "ignore" a return value in a meaningful way?
<mikdusan>
do you have a use-case in mind?
epmills has quit [Remote host closed the connection]
<betawaffle>
no, i'm just thinking about if someone can implicitly/accidentally ignore the return of something that allocates a resource the caller is responsible for
bheads has quit [Ping timeout: 268 seconds]
bheads_ is now known as bheads
<bheads>
ownership issue
<mikdusan>
yes, with `_ = call();` syntax
<betawaffle>
but that's not accidental nor implicit
<mikdusan>
sorry that's explicitly .
<betawaffle>
which is fine
<betawaffle>
i'm fine with explicit ignoring
<bheads>
still a footgun
<betawaffle>
and in that case, presumably the _ is still an actual location in memory the result is written to
shakesoda has quit [Remote host closed the connection]
<betawaffle>
even if the caller doesn't use it later
<betawaffle>
such as the location of the frame in _ = async foo()
<betawaffle>
(which is can make sense if the callee uses @frame)
<betawaffle>
s/is//
<mikdusan>
I think it has to be an actual location in memory, otherwise compiler would need to emit 2 calling conventions for the same fn body?
<betawaffle>
my understanding is something like `defer async foo()` would be a compile error but `defer _ = async foo()` would not be
<betawaffle>
basically what the issue is saying is that situations where a void result location is provided can only have expressions that *provide* a void result
<betawaffle>
right?
<betawaffle>
like... the result location is the location of a `void` value, and type-checks as such
shakesoda has joined #zig
<mikdusan>
I don't really follow
<betawaffle>
which part?
<mikdusan>
my (limited) understanding is usually the callsite would provide the void result location. but because "defer" is added to a list, the call-site of defer is not appropriate for the void result location.
<mikdusan>
thus defer _provides_ a void result location that is somewhere not at call site
<mikdusan>
err i should say defer is a statemen site.
<betawaffle>
well but void is zero-length, so anywhere should be sufficient
<mikdusan>
there could be tricks like that but those are impl details I think
<fengb>
async foo() returns a frame, not zero size
<betawaffle>
right, which is why `defer async foo()` would be a compile error, presumably
<dingenskirchen>
I'm trying to have both a dynamic library and a regular executable depending on it, both in pure zig. When I don't link against libc, however, the executable will segfault, and ldd doesn't list the interpreter. The file can still be run by calling the interpreter with the binary as an argument.
<dingenskirchen>
Is that intentional behavior/do I need to link against libc to have dynamic libraries?
<betawaffle>
i would imagine so, yes
<betawaffle>
you can't load dynamic objects into a static executable, afaik
<companion_cube>
is there a rationale behind this? :)
<companion_cube>
I'd imagine dlopen is stable, or is it not?
<betawaffle>
companion_cube: you asking me or dingenskirchen?
<companion_cube>
any of you, I know little about what's a stable syscall and what's libc-specific
<pixelherodev>
I think you can link a dynamic executable w/o libc though...
<betawaffle>
well, stability of syscalls is OS-specific
<mikdusan>
also there is libdl.a
<betawaffle>
linux is basically completely stable, but macos and some others are definitely not
<companion_cube>
yeah I was indeed thinking of linux
<pixelherodev>
Wait, shouldn't executables be dynamic by default for Linux?
<pixelherodev>
Since they link against glibc?
<pixelherodev>
Unless musl is the default
<companion_cube>
musl is default on alpine at least
<betawaffle>
linking against libc is recommended (or not, depending on who you ask)
<betawaffle>
for one, it can make your binary smaller, and use less memory for code
<fengb>
BSD and macOS only guarantees ABI stability in the C dynamic library
<betawaffle>
and stuff like solaris don't even have a syscall ABI at all
<fengb>
Linux syscalls are stable, and you can build against musl to guarantee a static executable, but I think the "native" for most systems would be glibc
<pixelherodev>
Eh, I've only ever linked Zig with libc when necessary
<pixelherodev>
Mostly when using a C-based library that requires the C allocator
<fengb>
Hmm good point. For some reason I assumed (poorly) that debug.warn would go through glibc
<betawaffle>
i think it does if you're already linking with libc for some other reason
<pixelherodev>
I... don't think that's true
<betawaffle>
really?
<pixelherodev>
Going to double check
<pixelherodev>
But I'm 99% sure it's just `try getStdOut().write`
<betawaffle>
i think for all the syscall-level parts, it uses libc if you're linking with libc
<betawaffle>
like, the write syscall, for example
<betawaffle>
but maybe i'm wrong
<pixelherodev>
Nope
<pixelherodev>
I mean yes
<pixelherodev>
That is, it doesn't ever go through libc
shakesoda has quit [Remote host closed the connection]
<betawaffle>
yeah, so anywhere that `os.system` is used, then
<pixelherodev>
... I honestly completely forgot about that
<pixelherodev>
Yeah, I take that back, it *does* go through whichever libc is linked in when applicable
<pixelherodev>
That's... odd
<betawaffle>
doesn't seem that odd to me
<betawaffle>
it also allows the user to override `system` with their own stuff too, it looks like
<pixelherodev>
Yeah, but that's unrelated
shakesoda has joined #zig
<pixelherodev>
Huh - the glibc write implementation was annoying to fully grok, but the macro seems to resolve straight into a write() syscall, making it 100% identical to the Zig-native Linux backend
<pixelherodev>
And TBH it was mostly annoying because Github sucks
<scientes>
pixelherodev, i recommend looking at musl over glibc
<scientes>
glibc loves to take you through 4 files before you fine the actual code
<pixelherodev>
Sure, but that's not the point
<pixelherodev>
I was curious specifically about glibc's implementation
<pixelherodev>
I expect musl's implementation to be a lot nicer, I was curious if glibc had extra overhead
<companion_cube>
pixelherodev: doesn't github have jump-to-def now? (although maybe it doesn't like C with macros)
<fengb>
C doesn't even like C macros
metaleap has joined #zig
<betawaffle>
that's literally one of the reasons zig is even a thing
<pixelherodev>
C macros are proof that life is meaningless
<pixelherodev>
Okay maybe that's a slight exaggeration but only slight
<companion_cube>
and C++ still didn't get their mess cleaned with #include
<pixelherodev>
C++ is just C but with more bad stuff thrown on top
<pixelherodev>
Actually, it's worse - C++ is the *worst* parts of C with more complexity-laden garbage thrown on top
<scientes>
pixelherodev, and they haven't stopped making it woorse!
<pixelherodev>
Templates and the C++ standard library alone suck
<pixelherodev>
I like Torvald's rant on C++
<scientes>
but there are SOOOO many c++ features
<betawaffle>
link?
<pixelherodev>
s/suck/suck worse than most entire languages I've used/
<companion_cube>
he became a human being with empathy, I find it better
<betawaffle>
he still tells it like it is, just with less fanfare
<companion_cube>
less gratuitous insults
<pixelherodev>
Yeah, he tends to rip into the mistakes more than the people now from what I've seen
<betawaffle>
i mean, calling people who use C++ is wholly unnecessary
<fengb>
C++ is an ~octopus~ centipede made by stapling legs to a dog
<companion_cube>
exactly
<pixelherodev>
Anyways, favorite quote from that: If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one?
<scientes>
or even a thunk
<scientes>
because C doesn't need thunks
<fengb>
I use thunks all the time in JS. I hate it every time >_>
<pixelherodev>
Though the one that most accurately reflects why I personally dislike C++ is this one: `Whenever the C++ language designers had two competing ideas as to how they should solve some problem, they said, “OK, we’ll do them both”.`
<Snektron>
Whats a thunk?
<pixelherodev>
`a subroutine used to inject an additional calculation into another subroutine`
<pixelherodev>
According to a quick duck :)
<betawaffle>
haskell uses the term to mean a strict evaluation, as opposed to a lazy one
<companion_cube>
otoh RAII seems pretty useful to me
<betawaffle>
or rather that a lazy evaluation results in a thunk that is then resolved later
<fengb>
Thunk is bastardized continuation passing style
<Snektron>
I see
<Snektron>
Also, don't forget how you're supposed to know an encyclopedia's worth of undefined behaviour cases
<fengb>
Instead of returning the value, you return a function that will evaluate the value later. Lets you set up lazy eval whenever and chain control flows, but it's really hideous to do anything useful
epmills has joined #zig
<Snektron>
pixelherodev, whenever i read virtual base i shiver
<Snektron>
especially when combined with pure virtual destructor
<Snektron>
Anyone using that must have written such an unholy mess it would call up cthulhu from the depths
* mq32
justed used goto in C# and doesn't even feel dirty a bit
<mq32>
the ability to break any block in Zig is just awesome and makes a lot of code much easier to maintain
epmills has quit [Quit: Leaving...]
<betawaffle>
Hah: "I think maybe the guy who invented C++ doesn’t know the difference between increment and excrement."
epmills has joined #zig
epmills has quit [Quit: Leaving]
<mikdusan>
:P. and I mean even the language creator goofed. ++C is more efficient
epmills has joined #zig
<mq32>
mikdusan, C++ is actually more efficient on a PDP-11 than ++C
<mq32>
that's why it was introduced in C
<mq32>
:D
epmills has quit [Client Quit]
<mikdusan>
hey is that actually true trivia?
<companion_cube>
I think C++ with a very small subset of features is still less bad than
<companion_cube>
C
<scientes>
no
<fengb>
Nobody agrees on the same subset
<mq32>
mikdusan, i can tell you first-hand that the PDP-8 has "fetch and increment memory" as a single instruction
<fengb>
Although a lot of people are with you companion_cube, hence even Zig is in C++
<companion_cube>
well, basic templated containers sure beat void* for me
<mikdusan>
mq32: neat. I was looking at https://en.wikipedia.org/wiki/Increment_and_decrement_operators "The PDP-7, however, did have a few 'auto-increment' memory cells, with the property that an indirect memory reference through them incremented the cell. This feature probably suggested such operators to Thompson"
<mq32>
mikdusan: and as the original PDP-11 also used core memory as storage, such an operation is a trivial op as you have to write-back to memory every read you do
<mq32>
core memory is a crazy technology
<mq32>
reading it destroys the content
<mq32>
so every read-op is also a write-ip
<mikdusan>
I think everyone in compsci should be made to thread their own magnetic core memory. at least once.
<mq32>
hehe
<mikdusan>
write-after-read sounds so much better than refresh for capacitors
<mq32>
and a lot slower ;)
<mq32>
i think it's a good idea to teach people that the current CPU model isn't "god given", but has evolved over time with a lot of side branches that never made it into the present time
<companion_cube>
if you want to teach stuff, at least teach useful/promising tech like risc-v :p
<companion_cube>
pdp11 is dead and can stay dead
<mq32>
companion_cube: it's always good to know what didn't work as well ;)
<mq32>
imho it's much more valuable to have bad experience shared than good experience, so you can rule out bad ideas much earlier in dev
<mq32>
imagine a tape where you don't move the tape but the data
<mikdusan>
ah
epmills has joined #zig
epmills has quit [Quit: WeeChat 2.7]
decentpenguin has joined #zig
epmills has joined #zig
<companion_cube>
mq32: I'm not too interested in hardware, really :p
<companion_cube>
as long as the compiler can generate decent code for it…
<mq32>
^^
<mq32>
and then you have to fix your compiler…
<mq32>
got to go
doublex has quit [Ping timeout: 240 seconds]
dimenus has joined #zig
epmills has quit [Ping timeout: 240 seconds]
doublex has joined #zig
doublex has quit [Ping timeout: 260 seconds]
bheads_ has joined #zig
bheads has quit [Ping timeout: 240 seconds]
bheads_ is now known as bheads
_Vi has quit [Ping timeout: 245 seconds]
decentpenguin has quit [Quit: decentpenguin]
redj has joined #zig
alexpana has joined #zig
<fengb>
I think all of these suspends cause indirect calls and prevent LLVM from optimizing well
<andrewrk>
that's unfortunate
<andrewrk>
I wonder if rust generators have solved this problem or not
<fengb>
A dirt simple suspend gets optimized away, but trying to store any value seems to confuse it
<andrewrk>
when doing these tests are you using --single-threaded ?
<fengb>
That speeds up execution by 10-50%
<fengb>
But the instructions are about the same. It does remove the atomic lock so there's a benefit
<andrewrk>
I see
<andrewrk>
if zig recognized generators in the language, we would be able to avoid atomic instructions
<andrewrk>
there should in theory be a way to communicate async functions to the optimizer to make it behave a lot better. this is an unfortunate limitation of llvm
<fengb>
Or overload the noasync keyword: `noasync async foo()` 🙃
<pixelherodev>
andrewrk, what do you mean it's a limitation of LLVM? What's stopping that?
<andrewrk>
it's looking at some IR and not seeing a bunch of optimizations it could be doing
doublex has joined #zig
<andrewrk>
whatever hints it would need to see the optimizations, zig has available, but there is no way to communicate it
<pixelherodev>
Hmm...
<pixelherodev>
Could it be added as metadata?
<pixelherodev>
If so, if I fix up my parser, I can probably write a self-hosted optimizer step that takes advantage of Zig-specific information
<andrewrk>
unrelated: apparently creduce supports (or at least handles) zig
<andrewrk>
creduce is a project that takes a large code sample and reduces it to a small test case
<pixelherodev>
ohhhh, I was reading that as cred-ooce; not C Reduce, so I had no idea what i was seeing
<pixelherodev>
That's awesome
<andrewrk>
also happy Windows 7 EOL day
<companion_cube>
I'm happier about python2 EOL 2 weeks ago
<andrewrk>
good riddance
<pixelherodev>
`if I fix up my parser` -> you know what, once I do that (get it able to successfully parse and generate an AST for all valid LLVM inputs) I'll ask again :P
alexpana has quit [Ping timeout: 268 seconds]
epmills has joined #zig
doublex has quit [Ping timeout: 260 seconds]
<andrewrk>
std lib is now allowed to unconditionally depend on windows 8.1 APIs even if they are not available in windows 7
<andrewrk>
although I suspect there's not really anywhere to take advantage of this
scientes has left #zig ["Leaving"]
scientes has joined #zig
doublex has joined #zig
alexpana has joined #zig
<fengb>
Guh, not a fan of Rust syntax :/
<companion_cube>
why not? it's pretty cool
<epmills>
i've had success cross-compiling one target at a time using 'zig build-exe'...
<companion_cube>
(I mean, turbofish is kinda weird)
<metaleap>
good evening all! my understanding of unions: no matter what tag is active, the overall memory cost for _any_ possible union value of a given union type will always be equal to the largest of the choices (plus the tag byte/int). hence in AST-type situations with multiple "small-value" choices and few "big value" choices I'd usually go for usize-or-pointer-rather-than-full-struct such as here: https://github.com/metaleap/atem/blob/master/cmd/src/atem.zig#L3
<metaleap>
3 thus all `Expr` values are no larger than necessary.
<metaleap>
BUT --- am I missing something? I can tell from here https://ziglang.org/documentation/master/std/#std;json.Value that every JSON node (incl. every true/false/null/float/int) will occupy the ~6 words that `std.json.ObjectMap` would occupy. is there some heuristic here I'm not aware of such as dereferencing being more costly than copies / cache lines on modern HW? sure i haven't benchmarked .. just itching to learn what I might be missing or if that's just
<metaleap>
"first throw, WIP" status
<fengb>
Syntax overload. e.g. match captures look like function calls but they're not
<epmills>
can someone point me to the syntax for multiple targets in a single build.zig? tia.
<fengb>
`GeneratorState::Yielded(y)` looks like a function call, but the y is a pattern matched variable
<companion_cube>
to me it just looks like a pattern
<companion_cube>
but I'm indeed used to ML
<companion_cube>
(and it's awesome)
<fengb>
That's ML if it had a bastard child with C syntax :P
<companion_cube>
heh, have you heard of reasonML ? :D
<companion_cube>
anyway, if you can think of a better syntax for sum types I'd love to hear about it
<fengb>
Also, Rust unstable generators have the same problem that I'm encountering in Zig
<fengb>
So... problem solved! :P
<Snektron>
i'd say the ugly part is that generators return a union even though its a language feature
<Snektron>
Theres nothing wrong with match statements in itsefl though
<fengb>
I'm accustomed to Zig's "if it looks like a function call, it is a function call"
<fengb>
And I don't think Rust activates the ML side of my brain like it should since it looks vaguely C-like
<companion_cube>
if it looks like a function call in a pattern position, then it's a pattern ;)
_Vi has joined #zig
epmills has quit [Ping timeout: 268 seconds]
mahmudov has joined #zig
<fengb>
"The 6502 gives you 256 bytes of stack" I think we're spoiled in the modern age
<metaleap>
so 2 doublecheck: if I read this `union` correctly https://ziglang.org/documentation/master/std/#std;json.Value every JSON true/false/null/int/float node will occupy the ~6 usize/words that's indicated by the biggest union member `ObjectMap`, right?
<fengb>
Oh sorry, I missed your question
<metaleap>
dont be =)
<fengb>
Normal unions have no defined memory. So it can be however big it wants
<metaleap>
oh so a `var someunionval : MyUnion` is variable-sized depending on the active-tag? neat. some langs the union is guaranteed to occupy tag+max no matter the active tag
<fengb>
The union is fixed size, but the compiler can reserve any space for it
<fengb>
So you can't rely on it having any fixed size other than figuring out at compile time
<metaleap>
ok i'm more pondering the worst-case --- fat struct (array / objmap) vs pointer-thus-also-usize like the int/float/ident cases
<fengb>
e.g. @sizeOf(union) is guaranteed to be consistent in one run, but not across runs
<fengb>
If you want fixed memory, you can do packed union, which will be sized according to the largest field
<metaleap>
if it pads further i dont care but in designing a union, do people tend to keep it tight or just "go wild"
plumm has joined #zig
<fengb>
It depends. Bare unions are useful because the compiler inserts safety checks for you and helps catching errors on using the inactive field
<fengb>
But if memory is a concern or you want to cast data types using a union, that's why a packed union exists
<fengb>
Packed unions also have no safety
epmills has joined #zig
leeward has joined #zig
<metaleap>
ah ok yeah makes sense. so any values typed `std.json.Value` could be "whatever size" (no guarantees) but WILL be at least ObjectMap size, lets face it? that much is unavoidable I must presume?
<fengb>
Yep
<metaleap>
whereas if the array/obj tags were pointer-typed, it would shrink to 1 or 2 words no matter the active tag? ok just wanted to be sure i have the correct understanding, thanx!
<plumm>
has anyone succeeded in passing function pointers to c functions?
<plumm>
uhh nvm
<epmills>
success, plumm?
alexpana has quit [Ping timeout: 268 seconds]
mahmudov has quit [Remote host closed the connection]
<plumm>
epmills: yeah *void
<plumm>
im wondering now how to curn *c_void back into what i originally had it as
<plumm>
trying a simple @ptrCast complains that it increases alignment
<fengb>
You can toss an @alignCast around that (probably to 16)
epmills has quit [Remote host closed the connection]
<plumm>
thanks fengb
epmills has joined #zig
<metaleap>
have a recursive func `foo` that returns `!Foo`. the inner `try foo(` subcall compiler-errors with: "cannot resolve inferred error set '@TypeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet"
<metaleap>
here i need to spell out the error set in full I gather?
<metaleap>
ah sorry for the noise, pointless question really :D
<epmills>
did anyone have thoughts on a sample build.zig that supports multiple targets (e.g. build to darwin, arm and linux in single zig build command)?
<plumm>
fengb: im trying to get a c *void to []u8 in zig, i have the cast down but im unsure on how to read the data from the pointer (i have the size). any ideas?
<metaleap>
fengb: thx, just `anyerror!Foo` does it for me, very handy.
<fengb>
I think one of the hidden costs of C is that nobody really notices multi-pointer and single pointer. I wasn't even aware of this problem until tinkering with Zig
<plumm>
thanks ill read that
<plumm>
also, have you encountered broken LLVM module found: Duplicate integer as switch case's ?
<plumm>
its switching on all values of an i32 but idk why
<plumm>
wait, maybe i do, 1sec
<metaleap>
Q: one member in a union type is an anon-struct-ptr aka: `const U = union(enum) { Ptr = *struct { foo: bar } }` --- there's no notation to initialize that other than extracting the struct-part out into its own identifier, or is there? like just saying `var u = U { .Ptr = &.{ .foo = ... } }` finds the 2 anon structs incompatible even if nominally / value-wise equiv
epmills has quit [Remote host closed the connection]
<pixelherodev>
Things formatted using std.fmt functions aren't null terminated
<bheads>
[:0]u8 is the correct way
<pixelherodev>
^
<pixelherodev>
A slice of type `[]const u8`.ptr gives you a `[*]const u8`; a slice of type `[:0]const u8`.ptr gives you a `[*:0]const u8`
<pixelherodev>
The latter is what C expects
<pixelherodev>
A pointer terminated by zero to an unknown number of `const u8`s
<plumm>
so arr[0..:0].ptr ?
<pixelherodev>
If that compiles, then I think so :)
<plumm>
ya, and it worked
<plumm>
neat
<pixelherodev>
Not 100% sure though, I haven't been using zero-terminated
<pixelherodev>
Nice!
<pixelherodev>
And thanks for reminding me to do the same :P
<fengb>
That also double checks to amke sure it's properly null terminated
<pixelherodev>
Not sure that I need to though, I'm mostly using literals
<fengb>
Yeah literals are guaranteed to be null terminated
<metaleap>
is that recent with null-terminated literals? i seem to recall in some vids the `c"literal"` notation. good for non-C-interopers to keep in mind that NULs occur, especially when concating lits with dyn strs........ (aka weirds me out as sth having to constantly keep in check)
<pixelherodev>
metaleap, that notation *was* used before sentinels were implemented
<plumm>
o
<pixelherodev>
So yeah, `c""` is no longer around
<pixelherodev>
Now, all string literals can automatically decay into any of `[]const u8`, `[*c]const u8`, `[*:0]const u8`, etc.
<pixelherodev>
So `c"'` isn't needed anymore
<metaleap>
pixelherodev: so that means everyone who never C-interops needs to chop the NUL off or the mentioned "decay" means that it's auto-dropped at compile-time depending on any sort of non-sentinel destination type?
<fengb>
No, we store the length without the null
<fengb>
So it just works™
<metaleap>
noice
<metaleap>
thx
<fengb>
Except the literal has an extra byte at the end so it'll be slightly annoying if you're space optimizing
<metaleap>
so much implicit magic behind this i-assumed-low-level lang :D but still a fan -- so far
<metaleap>
pretty ergonomic when one knows the rules, to be sure
<fengb>
It was a tradeoff to make literals work with C without having a separate string type
<fengb>
We used to have c"" for that, but it's a weird detail
<metaleap>
yeah actually quite a neat design given that constraint
<pixelherodev>
Yeah, but I'm still disappointed at the extra bytes :P
<pixelherodev>
Though, to be honest, even on the embedded platform I'm using it hardly matters
<andrewrk>
idk if I'd call it magic. zig and c string literals are exactly the same; zig just has more type information attached to them
<andrewrk>
C says, "idk it's a pointer I guess"
<andrewrk>
zig says, "it's a single-item pointer to an array of exactly N bytes, followed by a 0 sentinel"
<pixelherodev>
Technically, you could write a C compiler that gives you the same options
<pixelherodev>
e.g. an additional primitive type for slices
<pixelherodev>
But that would be nonstandard
<metaleap>
fair game :D if there's no pitfalls with the occasional mem.copy etc it should be dandy, and i guess here folks use the `.len`s at hand anyway
<pixelherodev>
It'd be interesting if compilers tracked that info anyways without exposing it for error checks
<pixelherodev>
So that e.g. character pointers would receive an implicit size
<pixelherodev>
I don't think it'd be easy, but doable and worthwhile, almost definitely
<fengb>
I mean, C should have been designed with fat pointers since the beginning :P
<companion_cube>
C should have been designed entirely differently from the beginning ;)
<leeward>
C's purpose was to take over the world, and it succeeded.
<companion_cube>
yeah, it's pretty sad
<companion_cube>
there were better languages than it before it was created
<leeward>
Better is a pretty subjective term.
<companion_cube>
better designed, less unsafe :)
<BaroqueLarouche>
man the C++ one " Bjarne Stroustrup bolts everything he's ever heard of onto C to create C++. The resulting language is so complex that programs must be sent to the future to be compiled by the Skynet artificial intelligence. Build times suffer. Skynet's motives for performing the service remain unclear but spokespeople from the future say "there is nothing to be concerned about, baby," in an Austrian accented
<BaroqueLarouche>
monotones. There is some speculation that Skynet is nothing more than a pretentious buffer overrun."
<fengb>
C unsafeness is one of the reasons it won
<leeward>
C's ease of implementation is probably the biggest reason it won.
<fengb>
Especially when hardware was so limited, "stop helping" was really important
<leeward>
There's a C compiler for that chip you're using.
<pixelherodev>
`1972 - Dennis Ritchie invents a powerful gun that shoots both forward and backward simultaneously. Not satisfied with the number of deaths and permanent maimings from that invention he invents C and Unix.` oh my
<pixelherodev>
This is amusing
<companion_cube>
glad at least one person got to discover this post
metaleap has quit [Quit: Leaving]
<plumm>
i seem to be getting an issue using that ptr trick, unsure of what could be the issue, but when using arr[0..:0].ptr, it seems to include another item allocated on the stack? i wonder why that is
mahmudov has quit [Remote host closed the connection]
<plumm>
actually wait no
<plumm>
well, i still dont know if arr[0..:0].ptr is the way to go, seems to be including things that normally arent supposed to be there
<pixelherodev>
Wait
<pixelherodev>
plumm, is this still generated by std.fmt?
<plumm>
yeah
<pixelherodev>
Add a `\x00` to the end of your format string
<plumm>
same alloactor to
<pixelherodev>
std.fmt still isn't null terminated
<plumm>
ok that worked lol
<plumm>
oh i thought doing the :0 would do that for me
<pixelherodev>
... that should be runtime erroring beforehand though
<andrewrk>
mikdusan, I could see it being useful. the implementation could be as simple as: const full = try allocPrint(allocator, format ++ "\x00", args); return full[0..full.len - 1 : 0];
<pixelherodev>
Because if there's no sentinel, trying to slice and verify the sentinel should fail
<andrewrk>
well you could make it generic across the sentinel if you wanted I suppose
lunamn has joined #zig
<plumm>
fengb: what do i do if that aligncast fails (incorret alignment) ?
<andrewrk>
oh I missed the first thing you said, " that should be runtime erroring beforehand though" - why do you think that?
<pixelherodev>
it's not zero terminated
<pixelherodev>
before the `\x00` was added
<andrewrk>
the safety is on the slice syntax; it asserts that `full[full.len - 1] == 0`. which it does, because we appended "\x00" to the format string
<pixelherodev>
But before that, it wasn't crashing, it was just giving the wrong result
<andrewrk>
before that we're calling allocPrint, nothing to do with sentinels
<pixelherodev>
Right, but slicing that non zero-terminated result should have failed
<pixelherodev>
Since it was being sliced with `:0`
<pixelherodev>
Oh wait I see
<pixelherodev>
It was being sliced with `[0.. :0]`
<pixelherodev>
No length specified
<andrewrk>
idk where you're looking, but my example code is return full[0..full.len - 1 : 0];
<plumm>
so instead of hardcoding the null term in the format string, i should do what andrew did?
<mikdusan>
plumm: err close. hardcoding the null term makes it legit to slice rv[0..rv.len-1:0]
<pixelherodev>
Hardcoding is needed regardless
<Snektron>
I just realized that if a language disallows logical and and or on non-boolean types, you could use | and & instead
<plumm>
ook
<pixelherodev>
andrewrk, I'm saying that what plumm was doing was slicing with `[0.. :0]`, which has no length parameter, whereas I *thought* length was being passed and the assertion wasn't detecting
<Snektron>
It seems really logical to use that, but on the other hand its also less readable
<andrewrk>
Snektron, that's related to simd, where you might have vectors of bools
<pixelherodev>
Summary: you need to have a null at the end. std.fmt doesn't do that, so you need to add it to the format string. Slicing a pointer from `[0.. :0]` slices from the beginning until a zero and marks that as the length. Slicing from `[0.. len :0]` would slice until len and assert that there was a terminating zero.
<pixelherodev>
So, what you want is to hardcode the zero in the format string so C knows the string's length, and if you know the length of the string, slice with that as a parameter so the language can assert the terminating zero is in the right place
<Snektron>
andrewrk, the semantics would be exactly equal to `and` and `or`, so if those can be applied to vectors | and & would be too
<Snektron>
Im surprised i don't know any language that uses bitwise operators for logical operators
<Snektron>
it seems like such a straight forward choice
<companion_cube>
well, doesn't work for negation, does it?
<andrewrk>
Snektron, `and` and `or` cannot apply to vectors of bools because control flow depends on the value of the LHS. but with a vector of bools you do not have a bool to look at the value of. it requires additional information: how to reduce the vector into a scalar
<Snektron>
a you make a good point, i didn't think of shortcutting
doublex has joined #zig
<Snektron>
That explains why nobody does it like that
<Snektron>
Do you think theres a case to be made for | and & on regular booleans, considering SIMD?
<pixelherodev>
... wait what?
<pixelherodev>
How would that even work?
doublex has quit [Read error: Connection reset by peer]
* mikdusan
is so confused; runs back to logo and commands a turtle
<pixelherodev>
If there's two booleans, SIMD isn't really applicable...
<pixelherodev>
mikdusan, what?
<pixelherodev>
logo? turtle?
<mikdusan>
programming lang
<leeward>
Wait, have you not heard of logo?
<plumm>
wow, it's been a while since ive heard that
<leeward>
pixelherodev, are you under 25?
doublex has joined #zig
<plumm>
im 19 so no ageism
<leeward>
I had a hypothesis. It's been falsified.
<pixelherodev>
Wait, you mean to quickly `&`/`|` together a large number of bools?
<pixelherodev>
leeward, 18, actually :)
<pixelherodev>
Not that I think it's entirely relevant
<pixelherodev>
Experience matters far more than age
<leeward>
Well, Logo was taught in schools when I was in school so it seems like maybe that's changed.
<fengb>
Spoken like a kid 🙃
<andrewrk>
Snektron, yes and that's planned if not already implemented
<Snektron>
great
<andrewrk>
and then @reduce for getting from a vector to scalar
<Snektron>
Logo was taught in my high school but the course was full
<pixelherodev>
Actually, now that I'm thinking about I do have some recollections of a turtle from towards the end of elementary school, but I don't remember all that much from back then :P
<leeward>
I remember making a little turtle robot move around when I visited the Boston Science Museum.
<plumm>
probably the python turtle package
<leeward>
Python had barely been invented the last time I used Logo.
<plumm>
that fails with the incorrect alignment thing i was talking about
<plumm>
on the var content line
<pixelherodev>
... really? Interesting...
frmdstryr has joined #zig
<pixelherodev>
Wait, at comptime?
<pixelherodev>
Or at runtime?
<plumm>
runtime
<pixelherodev>
Ahhh
<pixelherodev>
But wait a minute
<pixelherodev>
Without aligncast it fails
<pixelherodev>
With aligncast it fails
<pixelherodev>
With aligncast *if alignment isn't already correct*, it works?
<pixelherodev>
Wait a second, that shouldn't need to be aligned anyways...
<pixelherodev>
What if you remove, the alignCast from the var content line? Just ptrcast that?
<pixelherodev>
[*u8] shouldn't require a specific alignment AFAIK
<plumm>
hat works lol
<pixelherodev>
Yay!
<pixelherodev>
Four lines shorter, some unnecessary casts removed, and more readable. I call that a win!
<pixelherodev>
And also it works. That's important too :P
<pixelherodev>
Question
<pixelherodev>
plumm, is that string null terminated?
<pixelherodev>
`content` that is
<pixelherodev>
If so, you should add `:0` to the slice
<pixelherodev>
Also, since the size is known, maybe change the type of content to `*[size * nmemb :0]`?
<plumm>
ok, will do
<pixelherodev>
Then you can change the slice range to `[0..]` and the rest should be implicit
<pixelherodev>
Though I'm not sure if that type is valid if the size isn't comptime known
<plumm>
size is not comptime known
epmills has joined #zig
<pixelherodev>
Yeah, never mind on that second suggestion then :P
<pixelherodev>
`[*:0]u8` should be good though
<plumm>
slice of pointer must include end value
<pixelherodev>
?
<pixelherodev>
Ag
<pixelherodev>
Ah*
<pixelherodev>
Right no, if you can't change the type you need the slice to be `[0 .. size * nmemb]`
<pixelherodev>
Though you *might* be able to add `:0` to the end of that slice (`[0 .. size * nmemb :0]`), I'm not sure (haven't used sentinels much)
<plumm>
that works too, but im unsure why i'd to that
<pixelherodev>
It ensures that the string is null terminated
<pixelherodev>
Assuming you're dealing with null terminated data, it's a useful safety check
<pixelherodev>
`Assertion failed at /home/noam/Documents/Development/Builds/zig/src/ir.cpp:17795 in ir_get_var_ptr. This is a bug in the Zig compiler.` NOOOOOO
epmills has quit [Remote host closed the connection]
<leeward>
I want the literal string that is the name of the function I'm calling from.
<leeward>
Oh, there's no void required there; it's always going to return an error.
<pixelherodev>
Whereas mine is for an error handler that shows a UI option to retry the caller
<daurnimator>
plumm: no I haven't had time to finish it off
<pixelherodev>
?
<frmdstryr>
leeward: Shouldn't the error trace tell you where the error ocurred?
<Snektron>
i wonder if ErrorUnion!noreturn is a valid type
<pixelherodev>
Wouldn't it just be ErrorUnion?
<pixelherodev>
Wait
<pixelherodev>
I think that should be ErrorSet
<pixelherodev>
Not ErrorUnion
<pixelherodev>
It takes an error set and returns a member of it
<pixelherodev>
The idea of defining an error union as a type has only just occurred to me, though I'm not sure there's much use outside obfuscation / minimization
<leeward>
frmdstryr, I want to log these and move on.
<leeward>
and I don't want a full trace in the log
<leeward>
And yes, it should have been ErrorSet
<daurnimator>
woo, #3699 fixed :D
<leeward>
Also, I want to print these in ReleaseFast, where there are no error traces to look at.
<leeward>
\o/
<frmdstryr>
Was going to suggest using std.debug.printSourceAtAddress but Idk if the debug info is present
<plumm>
whats like an ergonomic way to do ?json.Value -> ?Value
<plumm>
uhh, where Value is some raw type from the json.Value union
<pixelherodev>
@as ?
<pixelherodev>
Oh, uh
<pixelherodev>
Hmm, it's optional...
<pixelherodev>
`@as(?Value, v)` ?
<Snektron>
const v: Value = if (value) castToValue(value) else null;