|
comedyblissoption posted:i like it and i think readable is a reasonable way to describe my preference as if it is objective
|
# ? Jul 23, 2016 22:14 |
|
|
# ? May 22, 2024 15:37 |
|
which of those approaches do you prefer? is there another approach? keep in mind that the second case where you have a const but you assign to it along branching paths might defeat the entire purpose of making a variable const in the first place when the logic gets complicated enough. intent might also not be reasonably analyzed by a compiler.
|
# ? Jul 23, 2016 22:18 |
|
generating an intermediate value to assign to a const is more complicated and more verbose. creating an intermediate function is also more complicated and more verbose. i haven't seen assigning to a const value along multiple branching paths and it might just be a terrible language design choice
|
# ? Jul 23, 2016 22:22 |
|
MALE SHOEGAZE posted:is that really true? don't languages like haskell just present you with an immutable interface for data but under the hood much of it is mutated anyhow because otherwise it would be super slow? nobody is saying literally never use in-place mutation. it's just about how many hoops the compiler makes you jump through, which (the theory goes) make code that uses mutation more likely to be correct. in some langs absolutely everything is mutable and you have no guarantees at all and it's poo poo
|
# ? Jul 23, 2016 22:30 |
|
you don't have to declare the function, just call a closure. this is fine for the small number of times that you actually want to do a switch just to produce an intermediate value and it doesn't make more sense to make that a general function for the type
|
# ? Jul 23, 2016 22:32 |
|
comedyblissoption posted:in list, an expression invoking a function is written with the following syntax: if it was just code:
what people are complaining about is code:
|
# ? Jul 23, 2016 22:35 |
|
MALE SHOEGAZE posted:is that really true? don't languages like haskell just present you with an immutable interface for data but under the hood much of it is mutated anyhow because otherwise it would be super slow? this is a really weird question under the hood, every programming language mutates memory. this is because computers do not come with the end-state of our programs burnt into rom i am positive that there are haskell optimizations that find ways to modify things in-place when they recognize that that's possible, or better yet avoid creating the original data structure when it's immediately discarded. if you're imagining that that applies super-commonly outside of very local things like chaining maps and filters, you are probably mistaken
|
# ? Jul 23, 2016 22:40 |
|
rjmccall posted:you don't have to declare the function, just call a closure. this is fine for the small number of times that you actually want to do a switch just to produce an intermediate value and it doesn't make more sense to make that a general function for the type this is what i think of when you say "call a closure" code:
|
# ? Jul 23, 2016 22:43 |
|
Soricidus posted:(there is no lisp equivalent because lisp doesn't confusingly create an implicit void value if you mistakenly use punctuation the way it's used in every single other braces language) i suspect they struggled with wanting lambdas to look like: code:
code:
maybe there's another reason
|
# ? Jul 23, 2016 22:48 |
|
if exprs are literally just different syntax for ?:
|
# ? Jul 23, 2016 22:49 |
|
i think comedyblissoption makes a good case wrt "everything is an expression" and ease of working with immutable values. i suppose you could make the case that the ternary operator helps but why have what's basically two different kinds of if statements?
|
# ? Jul 23, 2016 22:51 |
|
rather than continue debating the one thing perl got right, apparently, can one of the rust experts explain this bitquote:I would argue that the only real difference at the runtime level between programs you can write in LLVM and programs you can write in Rust is that Rust requires all of your programs to be safe, i.e. not have memory errors/data races
|
# ? Jul 23, 2016 22:54 |
|
comedyblissoption posted:can you give me an example of what this would look like assume for the sake of argument that the statement-based language we're talking about does have a ternary expression. this is a good bet because i can't think of any off-hand that doesn't. so this is literally just about switch yes, that is the general idea of the syntax. in swift it would be: Swift code:
Swift code:
|
# ? Jul 23, 2016 22:54 |
|
yah if expressions and ?: are equivalent except for the ternary typically doesn't support multiple lines in the branches you cannot be against if expressions while also being supportive of ?: because that would be contradictory rjmccall posted:the verbosity difference here is not huge I will agree the swift example is not as atrocious as it might be in c++ or c#.
|
# ? Jul 23, 2016 23:01 |
|
what exactly is gained by having if statements and ?: over if expressions?
|
# ? Jul 23, 2016 23:06 |
|
JawnV6 posted:goes on to say it does this without imposing any runtime constraints, couple paragraphs after claiming LLVM doesn't have loops as an example, rust tries to make it so that iterating over a vector is just as fast as handrolling the equivalent C or assembly iteration while providing a safe and high level interface to the vector
|
# ? Jul 23, 2016 23:08 |
|
i'm more interested in how it prevents data races without runtime cost, but the llvm loop thing is more about his abject unfamiliarity with llvm. there's an earlier post where an attempt to survey the field doesn't mention it. does rust let you query such a loop to determine if invariants can be hoisted? or is that a nonsensical question because the vector formatting doesn't permit hoistable invariants anyway?
|
# ? Jul 23, 2016 23:30 |
|
Rust doesn't have goto And, borrow checking. Basically "zero cost" here means the stuff you do has no extra cost but there's stuff you can't do. HappyHippo posted:what exactly is gained by having if statements and ?: over if expressions? Not having bad semicolon rules, also not walking yourself into having break and continue be expressions, and if you want goto statements, that really requires that if/else used as a statement be distinguishable at some level from if/else being used as an expression. sarehu fucked around with this message at 23:33 on Jul 23, 2016 |
# ? Jul 23, 2016 23:30 |
|
you can have if/switch as both statements and expressions, too. this poses no serious problems.
|
# ? Jul 23, 2016 23:35 |
|
JawnV6 posted:i'm more interested in how it prevents data races without runtime cost rust encourages heavily using references and moves you can declare references and values as either mutable or immutable (similar to const in c++) rust statically prevents you from aliasing mutable references not allowing aliased mutable references helps prevent violating invariants and prevents iterator invalidations rust uses type annotations to mark certain types as being safe to move or copy to another thread so that it can prevent unsafe moves or copies
|
# ? Jul 23, 2016 23:40 |
|
here is an article w/ more details if youre interested https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html i personally think after working on a C# codebase wrought w/ data race problems, statically guaranteeing youre not gonna gently caress up sharing data is important
|
# ? Jul 23, 2016 23:43 |
|
I've used Maxima, and its semicolon works the same way as Rust's. The best way to explain it is to say that the semicolon is a postfix operator that basically means, "Don't return this value" and lets you put another expression afterwards.
|
# ? Jul 23, 2016 23:46 |
|
the rust semicolon thing seems like a problem that's theoretically annoying but not actually a problem in practice. not that i've ever used rust
|
# ? Jul 24, 2016 01:26 |
|
the only way that a transpiler would ever produce safe, idiomatic rust code is if the source language was basically a safe, sugared subset of rust. you can compile c to rust, but you will have to wrap every pointer dereference in an unsafe block. you can compile javascript to rust, but all of the code you produce will traffic in some JSValue enum type that includes a shared gc reference. using rust as an ir does not give the source language any of the benefits of rustJawnV6 posted:i'm more interested in how it prevents data races without runtime cost rust has a lot of special checking to ensure that values are only used uniquely. like, if you have an array, you can get a pointer to an element, but now you can't use the original array anymore until you're done with the pointer; or maybe you pass the array off to someone else, and now you can't use the array anymore at all. there are a number of things that can benefit from this kind of checking. the race-condition thing is just that, if you've got something like a pointer and you know that nobody else has that pointer, you can be sure that dererencing it won't race if you do need something like a shared reference, there are types in the library for that, but they won't give you access to the memory unless you do something like take a lock. or they'll say that accessing the memory is an unsafe operation, so it has to be done in an unsafe block, and once you do that of course you can have races again. and rust forces basically everything that could possibly be unsafe to be done in an unsafe block, like calling a c function it's actually pretty neat, but it is an expert feature, and it does not interoperate well at all with existing systems JawnV6 posted:does rust let you query such a loop to determine if invariants can be hoisted? or is that a nonsensical question because the vector formatting doesn't permit hoistable invariants anyway? iteration in rust will do things like give you direct pointer access to the elements of the vector, so that the ultimate code approximates what a c compiler would produce, but it forces it to be done in a safe way. i don't know what sort of invariants you're thinking of to answer more specifically than that the loop thing is really weird, you are almost certain to not be able to transpile a loop from a different language into exactly a rust loop anyway
|
# ? Jul 24, 2016 03:21 |
|
rjmccall posted:... or they'll say that accessing the memory is an unsafe operation, so it has to be done in an unsafe block, and once you do that of course you can have races again. and rust forces basically everything that could possibly be unsafe to be done in an unsafe block, like calling a c function This is basically how I imagine a theoretical transpiler to rust would work. Start the program with a huge, fuckoff unsafe block, write everything there, done. And its also why its extremely dumb idea.
|
# ? Jul 24, 2016 09:11 |
|
comedyblissoption posted:that makes sense here's another solution that took me 0.00001s to think up: make the last semicolon optional. now you can have nice looking closures without adding an annoying source of compile errors! but nope rust devs just gotta get all cute with their syntax
|
# ? Jul 24, 2016 09:59 |
|
Soricidus posted:here's another solution that took me 0.00001s to think up: make the last semicolon optional. now you can have nice looking closures without adding an annoying source of compile errors! trust me, you don't want things to auto convert to unit (which i believe is the solution you're suggesting) scala does it and it drives me nuts
|
# ? Jul 24, 2016 11:02 |
|
gonadic io posted:trust me, you don't want things to auto convert to unit (which i believe is the solution you're suggesting) i don't know scala so idk what you mean by that. auto conversions are bad. rusts idea of appending something to the list of expressions to indicate that you don't want to return a value is good. making that thing be an empty expression indicated with an easily overlooked bit of syntax that has meant something different in basically every mainstream pl for decades is bad.
|
# ? Jul 24, 2016 14:06 |
|
if you read the semicolon as 'andThen' instead of as an expression terminator rust's design makes sense if you really hate it you can always insert explicit nil after the last semicolon
|
# ? Jul 24, 2016 14:34 |
|
wish I could convert this discussion to unit
|
# ? Jul 24, 2016 15:00 |
|
if you think about semicolons in code any harder than you think about periods in text I don't know what to say
|
# ? Jul 24, 2016 16:05 |
|
I don't read them as anything. they're just there, gluing bits of poo poo together
|
# ? Jul 24, 2016 16:06 |
|
rjmccall posted:the only way that a transpiler would ever produce safe, idiomatic rust code is if the source language was basically a safe, sugared subset of rust rjmccall posted:rust has a lot of special checking to ensure that values are only used uniquely. like, if you have an array, you can get a pointer to an element, but now you can't use the original array anymore until you're done with the pointer; or maybe you pass the array off to someone else, and now you can't use the array anymore at all. there are a number of things that can benefit from this kind of checking. the race-condition thing is just that, if you've got something like a pointer and you know that nobody else has that pointer, you can be sure that dererencing it won't race rjmccall posted:if you do need something like a shared reference, there are types in the library for that, but they won't give you access to the memory unless you do something like take a lock. or they'll say that accessing the memory is an unsafe operation, so it has to be done in an unsafe block, and once you do that of course you can have races again. and rust forces basically everything that could possibly be unsafe to be done in an unsafe block, like calling a c function i do different tasks in different languages, but working between them hasn't been a major pain point. it might fall into the "teach not want what they don't provide" loophole, but the kind of shimming necessary to drop python string handling into C no matter what IR doesn't seem like a good ROI even if the safety brush painting magically worked rjmccall posted:iteration in rust will do things like give you direct pointer access to the elements of the vector, so that the ultimate code approximates what a c compiler would produce, but it forces it to be done in a safe way. i don't know what sort of invariants you're thinking of to answer more specifically than that
|
# ? Jul 24, 2016 18:35 |
|
rjmccall posted:this is a really weird question in a program that does i/o, the whole universe is state
|
# ? Jul 24, 2016 19:42 |
|
JawnV6 posted:i was thinking it was either casting unsafe around anything remotely contentious or coming up with a lot of rules that would hamper performant code, if not literally invoking a runtime component to deal with it the exclusive access stuff doesn't require hardware awareness because you're just emitting unsynchronized accesses. things that share data between threads generally have to barrier to get transitive memory ordering of course the shared stuff doesn't, like, get implicitly optimized to use atomic accesses or anything. there's a standard library type which allows you pass a shared reference, but when you create it you're also creating a lock, and in order to access the memory you have to acquire the lock. it is not especially performant. there are also atomic types in the library, but you have to explicitly use them instead of a locked reference, and of course they have a more modest api surface JawnV6 posted:naively googling 'llvm loop' took me to the headers for loop operations on CFG elements. it seems like a decent set of operations i'd want if i had an IR and was mucking around with it before fixing into assembly. kinda falls into the same semantic benefit of the doubt he's giving rust elsewhere, "llvm doesn't have loops" vs "other languages won't have to implement loops because they'll use rust's"? llvm has an unrestricted basic-blocks-and-branches cfg, from which you can infer structure like loops, and which you can obviously lower loops to. structured control flow is hilariously low on the list of complexities that somebody writing a compiler wil have to face. (unstructured control flow, like gotos that can jump into the middle of inner blocks, is consistently annoying)
|
# ? Jul 24, 2016 19:43 |
|
rjmccall posted:structured control flow is hilariously low on the list of complexities that somebody writing a compiler wil have to face. It helps if you want to do loop optimisations, or parallelisation. But then this terrible idea to compile to Rust won't help anyway. (And I say this as someone who's pet language compiles to C/OpenCL, not LLVM.)
|
# ? Jul 25, 2016 09:01 |
|
"Spliterator" is both the best and the worst name
|
# ? Jul 25, 2016 10:36 |
|
Athas posted:It helps if you want to do loop optimisations, or parallelisation. not sure what you're saying here; i wasn't, like, arguing against the very concept of structured control flow, i was saying that it's not hard to compile and having nice builtin loop structures in the target language doesn't make much of a difference
|
# ? Jul 25, 2016 16:07 |
|
rjmccall posted:the shared stuff doesn't, like, get implicitly optimized to use atomic accesses or anything. there's a standard library type which allows you pass a shared reference, but when you create it you're also creating a lock, and in order to access the memory you have to acquire the lock. it is not especially performant. there are also atomic types in the library, but you have to explicitly use them instead of a locked reference, and of course they have a more modest api surface building things up from atomic primitives seems like the same point you'd be at with llvm as a target
|
# ? Jul 25, 2016 16:10 |
|
|
# ? May 22, 2024 15:37 |
|
JawnV6 posted:an implicit lock seems really opinionated on how synchronization should be done, and I'm guessing there's no support for a try/peek operation that gets the status without blocking to acquire? i'm apparently conflating a couple different things there's a type in the library which is a thread-safe reference-counted thing, but you can only get mutable access to the value if the reference count is 1 (which you can dynamically query) the mutex type builds in knowledge of the thing it protects. accessing that memory is not implicit, you call a lock method which blocks and gives you back something that you can modify. it does support a try_lock
|
# ? Jul 25, 2016 17:20 |