brolin_empey | KotCzarny: Yes, with “1.0/3” or “1/3.0” the result is correct. I forgot that integer division is different than decimal/float division. | 04:54 |
---|---|---|
DocScrutinizer05 | hail strict typing | 09:59 |
DocScrutinizer05 | this implicit typing is a mess | 09:59 |
DocScrutinizer05 | there shouldn't even be a thing like "integer division", only cast while assigning results to variables | 10:01 |
KotCzarny | say that to fpu less cpus | 10:02 |
DocScrutinizer05 | and it's the implicit hidden cast that makes me throw up. A decent compiler would throw an error or at least a bold fat warning when assigning a (possibly) non-integer result to an integer variable | 10:03 |
DocScrutinizer05 | int i = int( a / b ) | 10:04 |
DocScrutinizer05 | int i = a / b BZZZZZZZ JACKASS! | 10:04 |
bencoh | actually the current behavior is both sane and accurate | 10:05 |
DocScrutinizer05 | it is, but not obvious | 10:05 |
DocScrutinizer05 | as the description implies: it's implicit | 10:05 |
bencoh | you just should not expect a float result when dividing integers | 10:05 |
KotCzarny | that's a compiler's nuance, or language? | 10:06 |
DocScrutinizer05 | you always should expect a float result when dividing | 10:06 |
bencoh | it might be implicit, but nothing indicates it should not be the case | 10:06 |
bencoh | absolutely not | 10:06 |
KotCzarny | if language, it's ok, if compiler, it's black magic | 10:06 |
KotCzarny | (for new users) | 10:06 |
DocScrutinizer05 | it's langiage, for c | 10:06 |
bencoh | KotCzarny: C standard | 10:06 |
KotCzarny | then it's up to the user to learn properly | 10:07 |
bencoh | most probably K&R or c89, at least | 10:07 |
DocScrutinizer05 | it's prolly B already ;-D | 10:07 |
bencoh | haha, could be | 10:07 |
DocScrutinizer05 | aka: the most eloquent assembler ever made | 10:07 |
Maxdamantus | Just to be clear: the issue is implicit conversion, not implicit typing. | 10:12 |
bencoh | (or the lack thereof) | 10:13 |
bencoh | (which is a good thing in my opinion) | 10:13 |
Maxdamantus | The issue is its precense. | 10:13 |
Maxdamantus | presence* | 10:13 |
bencoh | ? | 10:13 |
DocScrutinizer05 | of course it's a matter of personal preferences | 10:13 |
DocScrutinizer05 | I lack half of the convo, sorry | 10:14 |
Maxdamantus | imo 5/4 == 2 is acceptable, 5/4.0 == 2.5 should be a type error. | 10:14 |
bencoh | Maxdamantus: ah | 10:14 |
bencoh | (5/2.0 I guess) | 10:14 |
Maxdamantus | er, yeah | 10:14 |
KotCzarny | imo current behavior of c is ok | 10:15 |
bencoh | KotCzarny: I think so as well, but ... :) | 10:15 |
Maxdamantus | I would probably also lean on the side of having separate operators for floating and integral division. | 10:15 |
DocScrutinizer05 | how do you add a ".0" to int i; ? | 10:15 |
bencoh | DocScrutinizer05: you cannot; you have to cast it | 10:15 |
KotCzarny | similarly to whole pointer thingy, tracking and remembering variable types and expected return types is up to the dev | 10:15 |
DocScrutinizer05 | :-P | 10:15 |
KotCzarny | in c++ otoh yeah, compiler should nag the poor user to death with warnings/errors | 10:16 |
KotCzarny | bencoh, i think i+=.0 will work ;) | 10:16 |
Maxdamantus | C has a bunch of other issues around implicit conversions, eg: int x = 4; unsigned y = -4; x < y; | 10:17 |
KotCzarny | unless you want to change type | 10:17 |
DocScrutinizer05 | in my book a operation (divide) that could yield a float WILL yield a float, always. If you want "integer divide" you got operators and cast for that | 10:17 |
Maxdamantus | eh, should've been the other way round | 10:17 |
KotCzarny | maxd: in that case you get a nice, juicy warning | 10:17 |
Maxdamantus | int x = -4; unsigned y = 4; y < x; | 10:17 |
bencoh | KotCzarny: i+=0. won't change anything to i | 10:18 |
bencoh | you cannot change the type of a variable | 10:18 |
DocScrutinizer05 | ORLY? :-D | 10:18 |
bencoh | DocScrutinizer05: I dunno why, but he seemed to imply that it would | 10:19 |
DocScrutinizer05 | hehehehe | 10:19 |
bencoh | (or was that sarcasm? :]) | 10:19 |
KotCzarny | bencoh, question was not clear (i've went with how to add .0 in value to i ;) | 10:19 |
bencoh | huhu | 10:19 |
Maxdamantus | 20:17:33 < KotCzarny> maxd: in that case you get a nice, juicy warning | 10:20 |
Maxdamantus | I don't seem to get any warning with `gcc -Wall -pedantic` | 10:20 |
KotCzarny | hmm, let me check | 10:20 |
Maxdamantus | That's using 4.9.3 though, a bit old. | 10:20 |
Maxdamantus | Still no warning with 6.4.0 | 10:21 |
bencoh | well, it's valid behavior, although I would expect a compiler warning as well | 10:21 |
bencoh | they do warn about unused variables, so ... | 10:21 |
bencoh | not warning about that is silly | 10:22 |
KotCzarny | oh right. it's in -Wextra | 10:23 |
KotCzarny | (in 4.9.2 at least) | 10:23 |
Maxdamantus | Heh, don't think I've ever used -Wextra | 10:23 |
KotCzarny | it's nice to catch some more obvious brainfarts ;) | 10:23 |
Maxdamantus | more obvious, or less obvious? Presumably less. | 10:24 |
Maxdamantus | Anyway, in a sensible language, that's just a type error. | 10:24 |
KotCzarny | more as in numerical number of them | 10:24 |
Maxdamantus | because you should have something like `(>) :: a -> a -> boolean`, where `a` is any given number type. | 10:25 |
KotCzarny | c assumes dev knows what he/she is doing | 10:25 |
Maxdamantus | So `(>) :: unsigned -> signed -> boolean` is not valid. | 10:25 |
KotCzarny | and if you know that int x wont get into negatives or y more than half of the type, it will work | 10:26 |
KotCzarny | many bugs prove it wrong though ;) | 10:26 |
KotCzarny | but that's C, love it, learn it or go into some sandbox | 10:26 |
KotCzarny | it's like trying to apply political correctness to the programming language | 10:27 |
Maxdamantus | Those are exclusive, right? | 10:28 |
bencoh | Maxdamantus: both learn and love C, you mean? | 10:28 |
Maxdamantus | bencoh: yes. | 10:28 |
bencoh | I somehow fell in love with it :) | 10:28 |
Maxdamantus | I mostly just got amused by figuring out weird things based on reading the standards over and over again. | 10:29 |
Maxdamantus | eg, like how you can pass arrays to functions in C90 but not C99. | 10:29 |
Maxdamantus | but in either case, you can't do anything with those passed arrays. | 10:29 |
bencoh | their are some standard oddities, yeah | 10:29 |
bencoh | there* | 10:29 |
Maxdamantus | though gnu89 lets you use the array in those cases where you can pass it (but that's non-standard) | 10:30 |
KotCzarny | isnt string an array? | 10:30 |
KotCzarny | ;) | 10:30 |
Maxdamantus | Not exactly. | 10:31 |
Maxdamantus | in case anyone's interested with the array passing thing: struct a { int a[10]; }; struct a foo(void){ struct a r = {0}; return r; } void bar(int a, ...){} int main(void){ bar(42, foo().a); } | 10:35 |
Maxdamantus | In C90, that passes an array to `bar`. In C99 and C11 it passes a pointer that is invalid once control actually reaches the function. | 10:36 |
Maxdamantus | and in gnu89, I think you can actually write `int a[10] = va_arg(ap, int [10]);` to get it again. | 10:38 |
Maxdamantus | in C89 itself, you can at least write `va_arg(ap, a10);` given `typedef int a10[10];` (but not necessarily `va_arg(ap, int [10])`, since `va_arg` is only specified as taking an identifier as the type), but you can't do anything with it except pass it to another variadic since it's a non-lvalue of array type. | 10:41 |
Maxdamantus | another variadic function* | 10:42 |
bencoh | Maxdamantus: what do you mean by "array" in that case? | 10:45 |
Maxdamantus | bencoh: in which case? | 10:45 |
bencoh | is the whole array stored in the stack? | 10:45 |
bencoh | c90 | 10:45 |
Maxdamantus | bencoh: if you think about it as a stack and of all arguments being on the stack, yes. | 10:45 |
bencoh | that sounds odd tbh, but ... :) | 10:46 |
Maxdamantus | Usually you don't get to handle arrays as values. | 10:46 |
bencoh | (I mean, such a definition sounds odd) | 10:46 |
Maxdamantus | because array expressions end up just being pointers in all sensible contexts other than when they appear as the operand of &. | 10:47 |
Maxdamantus | but `foo().a` is a weird case, since `foo().a` is not an lvalue, so the array → pointer rule doesn't apply to it in C90. | 10:47 |
bencoh | yeah | 10:47 |
bencoh | ah | 10:47 |
bencoh | I see | 10:47 |
Maxdamantus | C99 added the extra case of non-lvalue array expressions though, so in C99 it does turn into a pointer, which means you can then access one of its members. | 10:48 |
Maxdamantus | (in C90, `foo().a[0]` is invalid when `foo().a` is an array) | 10:48 |
bencoh | sounds like a standard "bug" :) | 10:48 |
KotCzarny | is there any gain of passing it as array instead of just pointer? | 10:48 |
bencoh | (bug-by-design I mean) | 10:48 |
Maxdamantus | KotCzarny: it would be logically sensible to be able to pass array values around. | 10:49 |
bencoh | KotCzarny: well, the pointer is eventually invalid, while copied data would remain valid | 10:49 |
Maxdamantus | KotCzarny: C doesn't let you do that (except in this weird case), so when that's useful you pretty much just have to put the array inside a struct. struct values can be passed around. | 10:49 |
KotCzarny | so it might even be slower because it has to copy the function argument? | 10:50 |
Maxdamantus | KotCzarny: possibly. It depends how you're using it and what sort of optimisations the compiler is able to make. | 10:51 |
Maxdamantus | KotCzarny: you should compare it to something like structs .. sometimes it's useful to pass a struct value, sometimes it's useful to pass a pointer to a struct object. | 10:52 |
Maxdamantus | Logically, you should be given the same choice with arrays. It's probably just for historical reasons that you're not given that choice. | 10:53 |
Maxdamantus | in other modern languages that provide a C-style distinction between pointers/references and non-pointer/reference product types, they offer that choice properly. | 10:54 |
Maxdamantus | (particularly, Go and Rust) | 10:54 |
Maxdamantus | in Go, an `int[3]` value itself is equivalent to three ints, instead of being a pointer to an object containing 3 ints. | 10:55 |
Maxdamantus | So when you pass an `int[3]`, you're passing a copy of those three ints, just as when you pass an `int` or a `struct { a int }`, you're passing a copy of that int. | 10:56 |
Maxdamantus | You can make a slice (basically a pointer) out of it using something like `a[:]`, which is pretty much what C does implicitly whenever you write an array expression (other than when it's the operand of &) | 10:57 |
bencoh | actually, passing objects (others than standard int/float and pointers) as arguments always sounded odd to me | 11:00 |
Maxdamantus | objects are not things you pass, unless you mean reference/pointer. | 11:01 |
Maxdamantus | in languages like Java, "object" and "reference" are often conflated. | 11:01 |
bencoh | I mean passing a struct, for instance | 11:02 |
Maxdamantus | Ah. | 11:02 |
bencoh | it always looks wrong to me, although I know you can | 11:02 |
KotCzarny | i always think of struct as an array with multiple types inside | 11:03 |
Maxdamantus | Well, if you have something like a 2D vector, you'd normally want to pass a single value containing both components. | 11:03 |
Maxdamantus | Passing a pointer in that case would be a bit like passing a pointer every time you wanted to pass a single number. | 11:03 |
KotCzarny | but for a compiler it's just memory area | 11:03 |
Maxdamantus | also, it's often a lot cleaner being able to return structs than having to take in a "return pointer". | 11:04 |
Maxdamantus | `struct player player = new_player(4, 5);` rather than `struct player player; new_player(&player, 4, 5);` | 11:05 |
Maxdamantus | imo the former is nicer .. some might disagree. | 11:05 |
Maxdamantus | and obviously with the 2D vector example .. `point x = plus(dot_prod(a, b), dot_prod(c, d))` rather than `point x, ab, cd; dot_prod(&ab, &a, &b); dot_prod(&cd, &c, &d); plus(&x, &ab, &cd);` | 11:09 |
KotCzarny | latter has a bonus of not needed for additional variable | 11:09 |
KotCzarny | *no need | 11:10 |
Maxdamantus | Indeed. | 11:10 |
Maxdamantus | (former, rather) | 11:10 |
KotCzarny | the one that takes &result as a func param | 11:10 |
Maxdamantus | It's the other one that has fewer variables. | 11:11 |
Maxdamantus | The latter has to declare variables to store the "results" of `dot_prod` | 11:11 |
KotCzarny | i meant that compiler doesnt have to copy the result | 11:11 |
Maxdamantus | (`ab`, `cd`) | 11:11 |
KotCzarny | and just operate on result itself | 11:11 |
Maxdamantus | If either is faster, I'd expect it to be the former. | 11:12 |
KotCzarny | you can't overload operators in c, so it's not that useful there (but has its uses) | 11:13 |
Maxdamantus | since it would probably end up just splitting the struct values across different registers. | 11:13 |
Maxdamantus | so `dot_prod(a, b)` would essentially be compiled down to `dot_prod(a.x, a.y, b.x, b.y)` | 11:13 |
KotCzarny | aren't you passing pointer? | 11:13 |
KotCzarny | well, mem address to a struct | 11:14 |
Maxdamantus | No. `point` is meant to be a plain struct in both cases. | 11:14 |
Maxdamantus | typedef struct { double x, y; } point; | 11:14 |
KotCzarny | tbh i dont know if you use only one field of the struct in function to cause compiler to unpack it wholly | 11:14 |
KotCzarny | i would assume it just acts as if that was a pointer | 11:15 |
Maxdamantus | There shouldn't really be anything to "unpack". | 11:16 |
Maxdamantus | aside from potential padding, wrapping things inside a struct in C should normally be a zero-cost abstraction. | 11:16 |
Maxdamantus | `struct { int a; }` should be passed around pretty much the same way that an `int` is passed around. | 11:16 |
Maxdamantus | in memory, they should look the same. | 11:16 |
Maxdamantus | That's contrary to an object in Java .. if you write `class Wrapped { int a; }`, that's not a zero-cost abstraction. | 11:17 |
Maxdamantus | since any `Wrapped` value is a pointer. | 11:17 |
Maxdamantus | They're specifically working on fixing that issue by creating a new concept called "value classes" | 11:18 |
Maxdamantus | http://openjdk.java.net/jeps/169 | 11:18 |
bencoh | "working" on that kind of stuff, in 2018, sounds kinda funny, for a 20yo language :) | 11:19 |
Maxdamantus | Well, most languages in the last 20 years haven't provided such a thing. | 11:19 |
Maxdamantus | in most languages all you've had is objects. | 11:19 |
Maxdamantus | and maybe a finite number of non-reference primitive types. | 11:20 |
Maxdamantus | (because of that, "primitive" is often taken to mean "non-reference" nowadays) | 11:20 |
Maxdamantus | I suspect Go and Rust are pretty much the only relatively known-about languages that allow you to specify your own non-reference types. | 11:21 |
Maxdamantus | (made in the last 20 or 30 years) | 11:21 |
bencoh | C structs can be non-reference | 11:23 |
Maxdamantus | Yes, and C was made almost 50 years ago | 11:24 |
Maxdamantus | I'm saying that practically every well-known language made in the last 20 or 30 years has been unlike C in this regard. | 11:24 |
bencoh | ah, I see your point :) | 11:24 |
Maxdamantus | but they're now trying to fix it, since the concept already exists in Go and Rust, and they're trying to introduce it finally to Java. | 11:25 |
KotCzarny | since i'm fixing up sysarm product i would prefer to wait until one is available (if you can arrange similar value, ie. ~55months of 4TB in /ca) | 11:29 |
KotCzarny | whoops | 11:30 |
KotCzarny | wrong chan | 11:30 |
Generated by irclog2html.py 2.17.0 by Marius Gedminas - find it at https://mg.pov.lt/irclog2html/!