ChanServ changed the topic of #zig to: zig programming language | ziglang.org | be excellent to each other | channel logs: https://irclog.whitequark.org/zig/
dd3 has quit [Ping timeout: 256 seconds]
cenomla has quit [Quit: cenomla]
benzrf has joined #zig
<benzrf> hi, i was looking over the zig docs & was wondering:
<benzrf> how exactly does "strict aliasing" work in zig?
<benzrf> because in C, the precise rule AIUI is that you can't deref a pointer whose type is different from the "effective type" of the object it points to
<benzrf> but the docs do this: https://i.imgur.com/4zH7l0F.png
<benzrf> so i assume the rule is different in zig?
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
klltkr has joined #zig
davr0s has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
klltkr has quit [Ping timeout: 240 seconds]
<andrewrk> benzrf: you found a serious bug in the docs. My apologies, I did not catch this when I reviewed the patch
<andrewrk> I'm going to see if I can add a runtime safety check for this so that it will panic
<benzrf> haha
<benzrf> which patch?
<benzrf> that seems like itd be hard to add a check for, though, unless you carry around type info with each pointer?
davr0s has joined #zig
<aiwakura> andrewrk I'm having a weird error
<aiwakura> in zen
<aiwakura> I'm trying to update build.zig to use a bunch of catch unreachable
<aiwakura> wanna give it a try?
<aiwakura> I must be doing something really dumb
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
cenomla has joined #zig
cenomla has quit [Quit: cenomla]
davr0s has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
Tobba has quit [Ping timeout: 268 seconds]
klltkr has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
pradam has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
Hejsil has joined #zig
Topa has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
Hejsil has quit [Quit: Page closed]
davr0s has joined #zig
<andrewrk> benzrf, it might not be possible to check in all cases, but maybe some common cases can be prevented
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
<andrewrk> aiwakura, -> is removed
<andrewrk> and return types are required now
<andrewrk> even void
<GitHub175> [zig] andrewrk pushed 2 new commits to master: https://git.io/vNSmE
<GitHub175> zig/master 2b5e0b6 Andrew Kelley: std: fix fn return syntax for zen os
<GitHub175> zig/master abe6c2d Andrew Kelley: allow packed containers in extern functions
<MajorLag_> You know what I really like about Zig? var flask = dungeon.GetYeFlask() ?? exitWithMessage("You can't get ye flask!"); Handling the null without all the busywork means I'll actually handle the null for a change.
<benzrf> MajorLag_: that's a feature of most languages that distinguish between nullable and non-nullable in the type system :p
<benzrf> e.g., haskell, rust, the MLs
<MajorLag_> maybe, but those have other things I don't like about them.
<benzrf> e.g.?
<benzrf> oh you mean the language as a whole rather than the specific nullability stuff?
<MajorLag_> yeah, I like that Zig is as low level as C and doesn't try to force me into some idealistic paradigm, but has quality of life improvements like the above.
<MajorLag_> And actually has a decent level of documentation, unlike some other "better C" alternatives I could name and also fund.
<benzrf> "forcing into idealistic paradigm" is a product of viewing what you're used to as "normal"
<MajorLag_> maybe
<benzrf> but i probably shouldnt be getting into PL wars right now
<benzrf> or in this channel
<benzrf> zig definitely looks nice for writing ABI-compatible code, though
<benzrf> i've been writing a toy garbage collector for my toy compiler and zig looks like it'd be a gr8 step up from C for that purpose
<benzrf> i like rust from what i've seen of it, but it's absolutely not suitable for poking around in the stack
<MajorLag_> What I mean is the difference between "you can't ever do X because it's Y. You have to do it by using our overly abstracted idiomatic mechanism...". I've yet to run into an instance in Zig where I can't do something, i just have to reassure the compiler that I mean what I'm saying occasionally.
<benzrf> does zig have computed jumps
<benzrf> cuz i bet asm writers from decades ago would think it's idealistic and child-padded to not allow that :-)
Hejsil has joined #zig
<benzrf> in any case, i wrote a separate garbage collector of a different style (mark-and-sweep) before this, but i had to implement an interpreter first so that i'd have something to gc for - i initially tried writing it in rust, since it seemed much nicer than C for writing an interpreter, but i realized pretty quickly that rust is specifically designed to prevent you from setting up the kind of data structures that a
<benzrf> gc would operate on
<benzrf> lol
<benzrf> you could technically use refcounted pointers or something but that would just make me feel silly to write a gc on top of
<andrewrk> benzrf, contrarian opinions are welcome here, as long as you follow the rule in the topic - "be excellent to each other" :)
<andrewrk> (I'm not calling you out, I'm responding to " i probably shouldnt be getting into PL wars right now")
<benzrf> well, part of the reason i said that is that i have work i'm supposed to be catching up on >w>
<benzrf> MajorLag_: i noticed that you said "overly abstracted" -
<andrewrk> benzrf, no computed jumps at this time. the idea is on the table
<benzrf> jeez
<benzrf> i was using it as an example because i assumed it wouldnt have them :P
<andrewrk> I mean you're not wrong. we just removed goto
<benzrf> hah
<benzrf> anyway, "overly abstracted" is a phrase that only makes sense if you look at each language in terms of how it abstracts over the hardware, rather than as a construct unto itself
<andrewrk> but if someone can come up with a use case for computed jumps, and there is not a reasonable alternative way to support that use case, that's a strong reason to make it work
<benzrf> will zig support tail recursion
<benzrf> neat
<MajorLag_> I'm curious what we mean by "computed jumps" in this context.
<benzrf> my aforementioned compiler was originally gonna target C, but C doesnt support mandating tail recursion, which is kind of critical for my use case
<benzrf> i ended up using llvm IR
<andrewrk> we also *might* ban, or otherwise require special syntax for, non-tail recursion
<benzrf> what
<benzrf> (i guess i wouldve had to switch anyway - C isn't terribly friendly to gc examination, but llvm has specific infrastructure)
<andrewrk> it might be opt-in. but we want to achieve compile-time known stack size for all threads
<benzrf> what do you mean by "compile-time known stack size"
<benzrf> for each function's frame? the max depth?
<andrewrk> yes
<benzrf> ...which one?
<andrewrk> e.g. you can guarantee no stack overflow at compile time, and when creating a kernel thread, you can create it with a small stack size guaranteed to not overflow
<benzrf> now THAT seems straitjacketing to me
<andrewrk> that's the reason for making it opt-in
<andrewrk> you get some nice benefits if you do it though
<benzrf> annotating every function call seems bananas
<andrewrk> you wouldn't annotate every function call, the compiler can figure out the call graph
<benzrf> oh
<andrewrk> you'd have to annotate: external function prototypes, function pointers, non-tail recursion
<benzrf> i suppose "recursion" is an overloaded term
<benzrf> that sounds like a hell of a mess
<benzrf> you'd need to be very very specific about what kind of behavior is allowed to get what guarantees
<benzrf> sounds kinda like rust to me ;)
<andrewrk> yeah. at this point it's just an idea. might not work out. obviously I wouldn't do it if it made the language to difficult to use
<andrewrk> *too. and yes I agree with that sentiment
<benzrf> well, to be clear - it sounds like an interesting idea if done right
<andrewrk> it's highly desirable for OS and embedded targets
<benzrf> i was just poking fun at how it seemed, to me, to be a bit at odds with the apparent language philosophy
<andrewrk> how would you characterize the apparent language philosophy?
<benzrf> from what ive seen, it seems like the zig approach would be to allow explicit tail recursion and then tell the user to not have cycles in their call graph
<benzrf> "avoid locally unsafe behavior unless the user says 'yeah i want that' but don't impose strong static guarantees in general, in order to get out of the user's way"
<benzrf> i may be wrong - i havent looked in depth
<benzrf> sorry, s/strong static guarantees in general/strong static guarantees regarding whole-program correctness/
<andrewrk> benzrf, that sounds fair. but we also try to give users tools to make their code robust and handle all the edge cases
<andrewrk> opt-in to having a statically determined stack size would be one such tool
Topa has quit [Ping timeout: 240 seconds]
Topa has joined #zig
<benzrf> i mean the elevator pitch doesnt sound too incompatible - i just mean that if you examine what you'd need to do to handle that goal really robustly, it seems like it would /end up/ being at odds
<andrewrk> that's fair
<benzrf> bbl
davr0s has joined #zig
<MajorLag_> benzrf made me curious, so I thought I'd try to implement computed jumps using nakedcc and an array of fn. So far I've managed to crash the compiler and discovered that it can't parse array initialization syntax for arrays of functions.
<benzrf> lol
arBmind has joined #zig
<benzrf> the compiler i mentioned writing is for a tiny subset of haskell
<benzrf> i wanted to try implementing something approximating the stg machine that ghc uses
<benzrf> which is based entirely on computed jumps...
<benzrf> i ended up tweaking the concept heavily to use the system callstack and tail recursion when possible
<benzrf> but it was a pain :v
<andrewrk> MajorLag_, are you sure you're just not forgetting `void`?
<benzrf> maybe i shouldve just targeted assembly
<andrewrk> []nakedcc fn()void{fn1, fn2, fn3}
<andrewrk> this worked for me
<MajorLag_> const nfunc = nakedcc fn() void; var arr: []nfunc = {a, b, c}; ==> error: expected token ';', found ','
<MajorLag_> ah, ok, I'm just doing array syntax wrong
<MajorLag_> for some reason
<andrewrk> maybe because array syntax is confusing
<MajorLag_> I don't think it is really, I'm just easily confused.
<MajorLag_> compiler still crashes though. I'll see if I can minimize the test case.
<andrewrk> it could be passing a number literal to assembly
<andrewrk> huh I don't have an issue for this. I'll open one. https://github.com/zig-lang/zig/issues/728
<MajorLag_> it's pretty minimal it turns out, just calling an empty nakedcc fn() void causes it
<andrewrk> oh, that makes sense
<andrewrk> wait, nvm the compiler shouldn't crash
<MajorLag_> yeah, and there's nothing in the fucntion body at all.
<MajorLag_> making it noreturn instead of void and adding a @panic didn't help
dd3 has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
<andrewrk> MajorLag_, do you think it should be legal to call nakedcc functions?
<andrewrk> and should you be allowed to pass parameters?
<andrewrk> hm. you'd have to specify the calling convention at the callsite
<andrewrk> so for now I'm going to make it an error
<MajorLag_> what are they for if you can't call them?
<GitHub35> [zig] andrewrk pushed 1 new commit to master: https://git.io/vNSrY
<GitHub35> zig/master 1c60f31 Andrew Kelley: add compile error for calling naked function
<andrewrk> MajorLag_, for entry points in a .o file
<andrewrk> or calling from assembly
<andrewrk> we could add support for specifying calling convention at callsite
<andrewrk> here are some examples of usage of nakedcc:
<MajorLag_> well, outside of my little experiment I'm not really sure what the use case would be, but that of course doesn't mean it doesn't exist.
<andrewrk> hm I think we could allow calling naked functions with no args
<andrewrk> and no return value
<andrewrk> you could also take a naked function and @ptrCast it to a normal function and then call it. that's valid
<andrewrk> I think that's the best way to call nakedcc functions actually.
davr0s has joined #zig
<MajorLag_> Would that end up wrapping it in a pro/epilog needlessly?
<andrewrk> presumably you want to be able to return from the naked function, right?
<andrewrk> it would have the prolog/epilogue of whatever calling convention you casted it to
<andrewrk> if you wanted it to be more like a goto, you could tail call it
<MajorLag_> Yeah, that makes sense.
jfo has joined #zig
<jfo> ++ opt in disallowed non tail recursion, -- mandatory same
jfo has quit [Client Quit]
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
Topa has quit [Ping timeout: 246 seconds]
Tobba has joined #zig
<benzrf> andrewrk: on the topic of my original question - is there a spec regarding what type compatability, etc, looks like, for the purposes of pointer aliasing rules
<benzrf> i see that there's some sort of allocator feature thing, tho the docu seems sparse, & how would that interact with this
<andrewrk> benzrf, not yet. and truth be told, we don't actually codegen the TBAA in LLVM yet
<benzrf> tbaa = ?
<andrewrk> so what is in the docs really is just: "warning: we're gonna have TBAA"
<benzrf> hah
<benzrf> type based ? aliasing?
<andrewrk> yes
<benzrf> oh alias analysis
<benzrf> aha
<benzrf> good thing my compiler writing has forced me to already get familiar with llvm ir :>
<benzrf> i wish they had a better specification of the semantics of non-integral pointer types :(
<benzrf> i'm using them for the gc intrinsics features, and its not clear to me whether im causing UB when i indirectly convert them into ints, which i have to do since i have some code that's generic over the data it handles
<benzrf> er, not "int"s, but integral types
<andrewrk> is there a particular problem you ran into?
<benzrf> no, im just paranoid because it's not very detailed - but this is unrelated to zig anyway
<benzrf> er, unless zig uses non-integral pointer types somehow?
<benzrf> in llvm
<andrewrk> no, all our pointer types are integral currently
<andrewrk> I don't have a plan to break from that
<benzrf> yeah, im just rambling about tangential stuff
<andrewrk> but if, for example, we could prove that a pointer size is never depended on, we could insert runtime safety checks alognside the pointer, in debug mode
<benzrf> i'm not sure what you mean by that?
<andrewrk> err, I mean insert data alongside the pointer, to use for runtime safety checks
<benzrf> oh
<benzrf> well i don't think that's what non integral pointer types do in llvm
<benzrf> i think they were just introduced for use in the garbage collection infrastructure
<andrewrk> for example, in zig, unless you specify `packed union` or `extern union`, @sizeOf(TheUnion) is not guaranteed to be minimal. it might have a secret field used for a safety check
<andrewrk> (in fact in debug builds it does, and you get a panic if you access the wrong field of a union)
<andrewrk> ah I see. zig ignores 100% of the garbage collection features of LLVM
<benzrf> yeah
<benzrf> they only exist to block optimizations that make it unclear how pointers are related to each other, which might destroy the information llvm needs to generate relocation info
<benzrf> ...as far as i can tell
<benzrf> like i said, the docu is pretty scant
<andrewrk> I'm just thankful we have LangRef.html at all :)
<benzrf> no kidding
<andrewrk> It's the 1 browser tab that I never close
<andrewrk> it just occurred to me that the TBAA LLVM supports has the concept of hierarchies because of inheritance, but zig can largely ignore that
<andrewrk> I'm really tempted to make it a rule that mutable pointer parameters in zig must not alias by default
<andrewrk> but it's pretty hard to enforce, somewhat easy to do on accident, and the undefined behavior only exerts itself sometimes
<andrewrk> on the other hand it allows for a decent optimization, and would eliminate the 1 way that rust can be faster than zig
<benzrf> define "alias"
<benzrf> can i pass two pointers where incrementing one would alias the other?
<benzrf> also - the majority of rust's supposed pain points are the rules that prevent you from causing UB because of that requirement
<benzrf> you'd have to contort yourself just as much to avoid the UB either way, but the compiler won't tell you that you fucked up
<benzrf> well.... i guess "you'd have to contort yourself just as much to avoid the UB either way" is arguable :v
<andrewrk> that's probably right
<benzrf> actually hmmmm no, what you're describing is a lot more limited
<benzrf> rust promises *global* non-aliasing, whereas you're just talking about within a given lexical scope, right? and even then, only for parameters
<andrewrk> example of what I'm proposing: https://paste.ubuntu.com/26485755/
<andrewrk> we already have this with putting "noalias" in front of a paramater (restrict in C)
<andrewrk> but this would make it the default
<benzrf> well, i get that example
Topa has joined #zig
<benzrf> i guess i dont know the semantics of noalias yet
<benzrf> how does noalias account for situations like i asked about, where one point can be used to get to another pointer even though they arent equal?
<benzrf> e.g. "int i[2]; foo(&i[0], &i[1]);"
<benzrf> does it have some sort of transitive requirement thing?
<andrewrk> hm let me think about this
<benzrf> sorry that was gibberish - does it have some kind of requirement that you can't have a relation between two pointers which is the transitive closure of certain operations
<andrewrk> it's a limitation of what you can do, directly through a single pointer
<benzrf> so as soon as i modify any of my pointers, then, all bets are off
<andrewrk> yeah
<benzrf> well, if that's your rule, i don't think "the 1 way that rust can be faster than zig" quite applies :p
<benzrf> that's a MUCH weaker guarantee the compiler gets to work with
<andrewrk> so in this example, this does violate it, if you for example did this in foo: *a[1] += 1; *b
<benzrf> wait, what?
<andrewrk> because you modified b through a
<benzrf> wait
<benzrf> oh
<benzrf> when i said "all bets are off" i meant the compiler no longer gets to assume anything
<andrewrk> I thought you meant a pointer indirection
<benzrf> you're saying i get ub if i modify any pointers?
<benzrf> oh wait
Topa has quit [Ping timeout: 240 seconds]
<andrewrk> what you aren't allowed to do, is change the bytes that ptr1 points to, and, doing so, also change the bytes that ptr2 points to
<andrewrk> where "bytes that ptr points to" is defined as whatever bytes you access via ptr
<benzrf> well, that really just defers the issue - what if i modify a and then do "b[-1]"
<andrewrk> if you promised that a and b are noalias, that violates it
<benzrf> well, then that leads back to the question i tried to ask - 16:12 <benzrf> sorry that was gibberish - does it have some kind of requirement that you can't have a relation between two pointers which is the transitive closure of certain operations
<andrewrk> I don't understand some of those words
<andrewrk> I'm not sure what transitive closure of certain operations means
<benzrf> is there a rule like - i have certain operations, like indexing and incrementing and taking struct children, and if i can connect two pointers by a sequence of these, then i'm violating the rule
<andrewrk> yeah I think that's right
<benzrf> harsh
<andrewrk> agreed
<andrewrk> you *usually* don't need to do it though
<andrewrk> which makes it an unfortunate missed optimization much of the time
<benzrf> immediate example off the top of my head -
<benzrf> what if i have some kind of data structure where there's one metadata node at the top, and i have a function where i pass in the top node plus a pointer to the child i wanna manipulate
<benzrf> oh wait the rule is just if i actually go and use the pointer i get from that?
<andrewrk> indirect pointers don't count
<andrewrk> that's fine
Topa has joined #zig
<benzrf> oh i see
<benzrf> so it only applies to operations which don't require a load or store
<andrewrk> exactly
<benzrf> ah that's a bit less harsh :)
<andrewrk> yeah. that's why it's tempting
<andrewrk> if we could provide reasonable debug runtime safety checks somehow
<andrewrk> I would 100% make that the default requirement
<benzrf> i feel like increasing the UB surface without making it statically harder to hit that surface is bad ergonomics
<andrewrk> I agree
<benzrf> runtime checks are all very well but they don't fully compensate at all
<benzrf> kk
<andrewrk> that's true. But we gotta go fast
<benzrf> ability to reason about a language is fundamentally inversely connected to its power
<benzrf> one has to give
<benzrf> well, depending on the definition of "power", of course
<andrewrk> maybe it's not so bad to leave it off by default, because you can always use the "noalias" keyword in speed bottlenecks
<benzrf> ¯\_(ツ)_/¯
<benzrf> so hmm hold on
<benzrf> actually wait i think i can figure this out nvm
<benzrf> yeah ok after reading this http://en.cppreference.com/w/c/language/restrict that doesnt seem all that bad at all
<MajorLag_> Did Zig used to have a "use" keyword? It's in my UDL which was copied from zig.vim, but it isn't in the docs that I can see.
<andrewrk> it still has it
<andrewrk> use @import("foo.zig");
<andrewrk> it's recommended to generally avoid it, but it's useful for example in this situation: https://github.com/andrewrk/tetris/blob/master/src/c.zig
<andrewrk> I might replace it or redefine it to only work in this use case
<andrewrk> unless someone really pushes the case that we should keep use and convinces me to keep it as is
<MajorLag_> Can it not be used on "std"? use @import("std"); => error: invalid token: 'use'
<andrewrk> maybe you're trying to use it in a scope other than top level
<andrewrk> which, I agree, if we have it then it should work at any scope
<MajorLag_> Yeah, it's in a test{} block
<andrewrk> currently not supported
<MajorLag_> That's fine, I have little use for it, I just didn't know what it was and my tests on using it for namespaces produced errors.
<MajorLag_> One way it could be useful, and you've probably already thought of this, is for struct composition, but that could be considered less clear.
<andrewrk> e.g. include the fields of another struct?
<MajorLag_> yeah, a syntactical convenience over having a member that is that struct.
<andrewrk> I'm not convinced that this is better than a member that is a struct
<andrewrk> aside from looking prettier
Hejsil has quit [Quit: Leaving]
<MajorLag_> Me either. I had to work with some kernel ABI facing Go code that used a lot of that and I'm not really sure it didn't just make things slightly more confusing.
<MajorLag_> And in your c.zig case, couldn't you have just declared: pub const stuff = @cImport({... and then in main.zig: const c = @import("c.zig").stuff; ?
<andrewrk> yes, that's true
<andrewrk> if you're trying to provide a particular API though, it seems like you should be able to do that
<MajorLag_> Well one place I can think of it being a problem in the general case is for readability. If I'm reading a Zig file with like 10 "use" imports, then I have no idea which one any given symbol came from. That's probably not a big deal though.
<andrewrk> that's the main reason use is discouraged
<andrewrk> also it helps the compiler go faster to avoid 'use'
<andrewrk> instead of telling the compiler to search for an identifier, you're telling it exactly where it is
<andrewrk> zig has to resolve all the use decls to look something up; it won't even load a @import("foo.zig") from disk until a decl through that import is accessed
dd3 has quit [Ping timeout: 252 seconds]
Vinski has quit [*.net *.split]
wishstudio has quit [*.net *.split]
wishstudio has joined #zig
Vinski has joined #zig
arBmind has quit [Quit: Leaving.]