ChanServ changed the topic of #zig to: zig programming language | | be excellent to each other | channel logs:
MajorLag has quit [Read error: Connection reset by peer]
MajorLag has joined #zig
steveno has quit [Quit: Leaving]
MajorLag has quit [Read error: Connection reset by peer]
MajorLag has joined #zig
<mgxm> andrewrk: the build manifest should be something like that?
belgin has quit [Quit: Leaving]
return0e has quit [Read error: Connection reset by peer]
return0e has joined #zig
MajorLag has quit [Read error: Connection reset by peer]
MajorLag has joined #zig
porky11 has quit [Ping timeout: 250 seconds]
MajorLag has quit [Read error: Connection reset by peer]
MajorLag has joined #zig
IntoxicatedHippo has quit [Remote host closed the connection]
IntoxicatedHippo has joined #zig
_whitelogger has joined #zig
_whitelogger has joined #zig
_whitelogger has joined #zig
_whitelogger has joined #zig
wootehfoot has quit [Read error: Connection reset by peer]
_whitelogger has joined #zig
hio has joined #zig
<hio> Generics are ununderstandable to me, both in java, in c# and in every other language I've ever used that uses generics
<hio> I like to compare it to an entire new hidden dimension like threading. I have to think one layer deeper everytime I have to parse some code that uses generics as if the code is multithreaded
<hio> If you think about it, that's exactly what generics are: multiple threads of code that can all happen at the same time where that T shows up
<knebulae> hio: that's not the right way to look at generics. It's no wonder you are confused.
<knebulae> hio: if you're on here, I'd be more than happy to show you a couple of examples that would make generics simpler for you.
<hio> I'm not convinced that it's possible
<knebulae> Well, generics can *get* complicated, but you're making it harder than it needs to be. :)
<knebulae> hio: well, O
<hio> T could be anything, how is that helpful ?
<knebulae> hio: well, I'd say, this is the first misconception: "multiple threads of code that can all happen at the same time where that T shows up"
<knebulae> hio: T is not magic :)
<knebulae> hio: let's say you have a very simple function. It adds to variables (language is not important): return X+Y;
<hio> it could literally be anything, how am I supposed to understand a piece of code if I dont know what can arrive at T
<knebulae> hio: follow with me for a moment
<knebulae> hio: do you understand the concept of a function that adds two numbers and returns the result (in any programming language that supports functions).
<hio> lol man I know how to program and I know how generics work, I'm just saying that I dont like them
<knebulae> hio: well, as with all programming, I'd say the devil is in the details. If you really understood, there would be no confusion ;)
<hio> maybe if you really understood, there would be agreement
<hio> Golang doesnt have generics and everybody loves how simple it is
<hio> that's a fact
<knebulae> hio: fact?
<knebulae> hio: I hate go.
<knebulae> hio: It's horrible. Typing and typing and typing, and don't get me started on error handling.
<knebulae> hio: people like go because of co-routines and all the built in network goodies. Not because it's a good language. Plus it has Google's $$ behind it.
<hio> error handling is stupid in Go, that's true.
<hio> i can admit problems, can you?
<knebulae> hio: ?
<hio> generics are too hard to parse when reading code, that's simply something you have to admit
<knebulae> hio: I disagree. In fact, I think generics make things clearer. For example, in C#, I know that a Dictionary<String, UInt64> is clearly a dictionary with strings for keys and unsigned int64s as values.
<hio> ok but it is never enough anyway. What kind of strings? what do the ints mean?
<hio> that's my point about generics, you might as well remove them because it's never good enough
<knebulae> hio: And the dictionary itself was written once. With generic types. Instead of several times over with pointer tricks or casting or multiple function entrypoints.
<knebulae> hio: and now you know why I offered to clarify for you. :)
<hio> ?
<knebulae> hio: In go, if I want a function to add two numbers, I would have to create several functions. Functions like AddInt8, AddInt32, AddUInt64...
<hio> lets be honest, you effectively have to do that anyway in your generic function
<knebulae> hio: with generics, I can create one function (in pseudocode), Add<T>(T: x, T: y). So now, in code, I can call Add<UInt32>(10, 20) and get 30. The Type name in the angled brackets gets substituted into the function for T. But remember, Zig at least is not a dynamic language.
porky11 has joined #zig
<knebulae> hio: therefore, at COMPILE TIME, what happens is the compiler will see every place you used Add<T> in your code, and for every type T (say you used int8, int32, int64 in code), the compiler will actually generate a function in code as though you had actually had an Add(int8, int8) function and an Add(int64, int64) function.
<knebulae> hio: at the end of the day, generics are an evolution of templates, which are (at the end of the day), just an evolution of macros.
<knebulae> hio: that's right... it's all actually syntactic sugar!
<hio> right and the price for that sugar is that I have to read an extremely cryptic generic function and attempt to understand it based on an abstract type T instead of real types
<knebulae> hio: well, generics do have their problems
<knebulae> hio: one I hate is that checking for the type at runtime in generic functions is generally frowned upon
<knebulae> hio: but sometimes it's absolutely critical to write compact and succinct code.
<hio> it's frowned upon because it shines a light on the leaky idea of generics where you effectively still have to check types and write type specific code, it's just hidden behind if else statements inside the generic function
<knebulae> hio: my favorite test of a new language and how well generics work is to write a 4 type ORM (string, int, double, date) and see how easy it is.
<knebulae> hio: well you clearly know what you're talking about; but it's comments like this that worry me: "ok but it is never enough anyway. What kind of strings? what do the ints mean?"
<hio> then you should have asked, what I meant was that a string is still not enough type information. What type of strings are allowed in that dictionary? What do they mean, are they keys to a database, passwords, hashes? Which ones should be allowed?
<IntoxicatedHippo> hio: If I have a variable which is a string how do I know what that variable is for?
<knebulae> hio: well, that depends on the function, just an with a non-generic function.
<knebulae> hio: I agree with your leaky abstraction comment about generics, but I would rather read 1 generic function with a switch statement on type than 3, 5, or 100 individual functions.
<hio> it wouldnt create 100 individual functions, you could still write a generic function that receives a void* and then you just have to cast and then do the logic. it's the same exact thing except without the cryptic T
<knebulae> hio: Also, generics are more useful in traditional OO languages. Think about methods that could work on many different types but must be re-written over and over again with slight variations because the types do not share the same base class. This is less of a problem in languages like Zig and Rust that use function composition (and Javascript that uses object prototyping)
<knebulae> hio: void eliminates the type safety guarantees the compiler provides. we could also just write in asm which has no concept of types.
<hio> Im not actually that good with go but it seems they had the right idea, you can cast any object to an interface and if it happens to implement that interface implicitly then you can work with it kinda generically without knowing its exact real type
<knebulae> hio: so you are telling me that it's easier to implement "interface", then track down and make sure it's implemented on that type than to look at a generic function and mentally sub the T for whatever type you're using? I mean it's literally the same thing as mentally substituting a type for void instead of T.
<hio> there is a point of diminishing and even negative returns when the type system is more complex and more annoying than the value it provides
<hio> we can see that with Rust
<knebulae> hio: agreed.
<knebulae> hio: but I will disagree on go.
<knebulae> C# got generics right, and they are a pleasure to use.
<hio> i disagree, c# is horrible to use
<knebulae> hio: to each their own
<hio> you cant even pass a SubClass object to a function that wants a BaseClass and then call .SharedFunction() on it and it will call the BaseClass.SharedFunction() instead of the SubClass.SharedFunction()
<hio> how stupid is that? think about that
<knebulae> hio: ?
<knebulae> hio: you would want alternative behavior? I'm confused.
<hio> void function(BaseClass bla) { bla.sharedfunction(); }
<knebulae> hio: I get it
<hio> now im calling that with a subclass that has implemented sharedfunction
<hio> yet it's still calling the baseclass' function even though the compiler obviously knows what im passing to it
<hio> for such a simple thing I need to use reflection. It just shows me: To hell with complex type systems
<hio> c# isnt even that complex and it's already leaky as hell
<knebulae> hio: in your subclass example, were you using the override keyword?
<knebulae> Because method shadowing in C# requires one of 3 conditions: the method itself must be virtual or abstract, or the derived method must be declared override
<knebulae> hio: C# isn't as leaky as you think.
<hio> ok sorry knebulae, I was speaking from memory. I found the sample I created that shows the problem:
<hio> it should be printing the specific class' function implementation
<hio> instead it's always the base
<knebulae> hio: no it shouldn't
<knebulae> hio: that's not what this code says
<hio> yeah I know because c# is arbitrarily implementing their own personal decision on how types should work
<hio> it might just as well work this way
<knebulae> hio: lol
<knebulae> hio: man, I know you know that's not how software works :)
<knebulae> hio: it's not like Anders doesn't know how to design a programming language ;)
<hio> wait I think that wasnt the correct sample
<knebulae> hio: First, you call ActorCompiler().CompileStatement(stmt). But you don't do *anything* with stmt. How do you expect a method to be called on an object you don't use?
<hio> i might have mixed some samples up
<knebulae> hio: ok
<hio> i dont remember what it was, see that's my point dude. Type systems are too complex
<hio> oh right, i remember. It was around the problem that inside the ActorCompiler.CompileStatement i couldnt call the right one from the stmt object. I would have to make a huge list of if (stmt is SubClass) blabla
<knebulae> hio: the reason C#'s type system is complex, as you say it, is because it is robust. Give me a few minutes, I'll show you.
<hio> you have to click "share" and get ur own link
<hio> this just shows me my own code again
<hio> or fork might work too
<knebulae> hio: ok, let me check
unique_id has joined #zig
<unique_id> Generics is just replacing T with the type you supplied. It's exactly like copy pasting a class and changing one thing about it. It couldn't be made any simpler.
<unique_id> It just saves you work
<knebulae> hio: see if that one works.
<knebulae> hio: you will see that you have to be more explicit with C# with method overriding, but what you want to do is easily within the capabilities of the system.
<knebulae> hio: I assume you are running into problems writing something using the actor model? plugins?
<knebulae> hio: You will notice the problem you were encountering with the DerivedClass3 example.
qazo has quit [Quit: 345345]
<knebulae> hio: the solution, especially using the actor model, is to explicitly mark your parent classes' methods as abstract/virtual then override in the subclass.
<knebulae> hio: I guess this site works differently than I thought.
<knebulae> so back to zig, lol, has anyone had issues calling c functions with varargs support?
<knebulae> hio: here was the very final result if you care:
Ichorio has joined #zig
IntoxicatedHippo has quit [Quit: Leaving]
hio has quit [Quit: Connection closed for inactivity]
SimonNa has joined #zig
shollrollah951 has joined #zig
qazo has joined #zig
shollrollah951 has quit [Quit: Leaving]
steveno has joined #zig
SimonNa has quit [Remote host closed the connection]
SimonNa has joined #zig
steveno has quit [Remote host closed the connection]
unique_id has left #zig ["Konversation terminated!"]
hooo has joined #zig
Zaab1t has joined #zig
Zaab1t has quit [Quit: bye bye friends]
errpr has joined #zig
<errpr> Is there a way to write a library that calls functions defined by the library user?
<j`ey> using function pointers?
<errpr> how do I get the pointer?
<errpr> okay I can write my library inside a struct and have the caller initialize the library struct with pointers to the functions, feels a tad clunky though
<knebulae> errpr: yes. that is how function callbacks work.
<hooo> zig has no concept of interfaces?
<hooo> im trying to think of why this would be necessary or how function calls are maybe good enough
<hooo> although I dont see why it shouldnt be good enough, yes it's clunky but whatever
porky11 has quit [Quit: Leaving]
steveno has joined #zig
<knebulae> hooo: functions are first class citizens in Zig. You can pass them just like you would values. They are function pointers without the messiness.
<hooo> he asked how a zig library could consume a struct with certain functions supplied by the user. So that implies that the library has a certain signature for functions it wants to expect and only the implementation for those functions is swapped
<hooo> the question is how this intent can be done cleanly and nicely
<knebulae> hooo: right. The zig manual indicates that a function "type" can be created like so: const call2_op = fn (a: i8, b: i8) i8;
<knebulae> hooo: Which could then be used in a function declared as such: fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8
<knebulae> hooo: So if the proper signatures exist, the compiler will enforce a "clean" interface with the user supplied functions.
<knebulae> hooo: if not all necessary pointers are provided, then the library can error out.
<hooo> anyone know what is going on here, it's trying to find some gcc lib even though I'm trying to just use a hopefully self contained musl std library for zig:
<hooo> ok i figured it out
<hooo> --library-path /usr/local/lib64 where my gcc libraries are
darithorn has joined #zig