Yeah so it turns out that languages which are human-simple to write are the most complex to typecheck and the languages which are the simplest to typecheck are the most human-complex to understand and write
@mcc It's been a long time since I wrote code in a strongly-typed language but I'll take strong type checking at compile time over trying to figure out what someone else's code does in a duck typing language.
Then again, I was trained as an applied mathematician / scientific applications programmer. Types are part of our innate toolset.
@AlgoCompSynth @mcc This is why I'm starting to feel like Crystal > Ruby for me (although I currently don't get to work with either). I know Ruby kind of has type checking now? But putting the types in another file seems perverse.
@andy_twosticks @mcc I work mostly in R/RStudio. The workflow is about as optimum as it can be, but even with that I still have run a lengthy validation suite that catches a few errors the syntax checker allows. And it's more of a linter than anything else.
R is garbage-collected, of course. I think that's
a) cheating, and b) a sign you don't care about resource usage.
@AlgoCompSynth @mcc Hard opposite here. I feel like the fact C doesn't clean up after itself is Why We Can't Have Nice Things. Coders will always make mistakes.
Rust's approach is … interesting. But I feel like making the language a lot more complex in order to avoid both memory leaks and garbage collection is probably the wrong (but a damn clever) idea.
@andy_twosticks @AlgoCompSynth R is an "offline processing"/batch processing language. This makes it well suited for GC. My understanding is GC languages can and often do match or beat exact languages on amortized resource usage, the problem is GC languages are bad at making time guarantees in interactive mode because GCs are an unpredictable element. I write a lot of soft realtime code so Rust is appealing to me for that reason.
Modern GCs behave no worse than manual memory management in terms of time guarantees, as everything happens incrementally and in parallel. Hard realtime GCs exist.
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks and let us not forget what happens in a manual environment when you free a huge quantity of data in one batch, eg delete a large dictionary or whatever. Much longer pause time than an incremental GC.
Though one assumes you don't do that in a time-critical place 😀
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks the memory safety in rust is awesome, except they insisted on building smart pointers (Box etc) on top of it for half-assed reference-counting memory management, though the last 30 years tells us that's not good enough.
Automated memory management requires a global not local (per pointer) view of liveness.
My most recent disappointment with garbage collection involves R and `tidyverse` pipes on some large-ish transit data in an 8 GB laptop. By breaking the pipe chains into single steps and forcing a garbage collect after each step I was able to run it.
1. Upgraded the laptop to 32 GB, and 2. Rewrote the code using `data.table`, which can do the heavy lifting in place, rather that having multiple copies of large tables lying around.
Laziness is not always a virtue, especially in large-scale scientific computing where getting bounds on resource usage during the software engineering process is fairly easy (compared to, say a compiler or a theorem prover).
"Laziness" ist just a funny word for saying "the work of a programmer is not free". Programmer time vs. execution resources needs to be judged on a case by case basis. Surprisingly often, renting a beefy EC2 instance is the economic choice over even beginning to optimize a piece of code. And even for code run at scale, considerations like time to market and turnaround time for code changes are important factors.
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks "laziness" is also a term usually used to paper over macho Calvinist attitudes to programming, ie The Programmer Must Do It All, with a corollary of The Programmer Is Infallible.
We're writing software so we automate things. GC is automation, and it gets rid of several whole bug classes arising from the Infallible Programmer fallacy.
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks As soon as you reject the concept of automation for your own software, you either admit to writing code with memory leaks or you need to build a bad and ad-hoc substitute for GC inside your application, and oh look, here comes yet another implementation of reference-counting smart pointers.
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks So currently we seem to have these flavours of language: 1) free for all, go write you a bug (C) 2) static (compile time) automation of (some) object lifetime (C++ and Rust) 3) static analysis of lifetime, plus static bounds on concurrent access (Rust) 4) dynamic detection of lifetime and explicit dynamic access controls (Java etc) but no static borrow checks
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks IMHO we are sorely missing the ultimate combination of static lifetime analysis and borrow checking, with a modern/complete/incremental GC for the corner cases that a static checker cannot infer.
Basically, Rust with GC instead of smart pointers.
Yes I know I just made everyone angry but really it is for the better 😀
@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks Rust is kind of halfway there: it has mutexes (runtime access controls) because nobody is insane enough to claim that a static access control checker can work for all cases in a concurrent environment.
It just needs to make the next step and realize that runtime lifetime analysis is also required 😀
If I understand the motivation for the design choices the Rust team made, it was to make "system programming" - presumably compilers / interpreters, operating systems, webservers, databases, browsers, etc. - easier to get right on a successful compile without sacrificing performance.
Of that lot I've only done operating system programming, and that was so long ago that doing it in assembly was still the norm. 😀 If I were writing an OS today I'd do it in Rust. Case closed.
Operating systems don't have time for garbage collection. They don't even have time for floating-point computation. But they do need dynamic memory allocation and concurrency, and Rust is designed so the compiler saves the programmer time.
@AlgoCompSynth @andreasdotorg @mcc @andy_twosticks also we are not running on 6502 and 68000 anymore. Cache locality is *critical* to performance, and you can often get measurable speedups using a compacting GC.
Admittedly the concept of "my data can move" is terrifying to people who were raised on C 😀 and there are terrible corner cases.
But you need to not think of GC as having only performance cost.
@phenidone @AlgoCompSynth @andreasdotorg @mcc @andy_twosticks Can I please be taken out of this thread please? If you notice that someone hasn't made a single reply, no need to keep them tagged into it while you argue.
edit: To be clear, Uxntal hasn't changed. It's the same language as it was, but writing type inference reveals its hidden intricacies, similarly to how writing a BNF notation for a language might also.
Checking them is not too difficult, at the moment I add their stack-effect to the top of the fall-through and it seems to work for most cases. I'm trying to find a case where I can break out, but so far so good.
To be clear, the function does return, but it returns outside of its own scope.
Devine Lu Linvega
in reply to Devine Lu Linvega • • •mcc
in reply to Devine Lu Linvega • • •Zorro Notorious MEB 😡
in reply to mcc • • •@mcc It's been a long time since I wrote code in a strongly-typed language but I'll take strong type checking at compile time over trying to figure out what someone else's code does in a duck typing language.
Then again, I was trained as an applied mathematician / scientific applications programmer. Types are part of our innate toolset.
Andy Jones
in reply to Zorro Notorious MEB 😡 • • •Zorro Notorious MEB 😡
in reply to Andy Jones • • •@andy_twosticks @mcc I work mostly in R/RStudio. The workflow is about as optimum as it can be, but even with that I still have run a lengthy validation suite that catches a few errors the syntax checker allows. And it's more of a linter than anything else.
R is garbage-collected, of course. I think that's
a) cheating, and
b) a sign you don't care about resource usage.
Andy Jones
in reply to Zorro Notorious MEB 😡 • • •@AlgoCompSynth @mcc Hard opposite here. I feel like the fact C doesn't clean up after itself is Why We Can't Have Nice Things. Coders will always make mistakes.
Rust's approach is … interesting. But I feel like making the language a lot more complex in order to avoid both memory leaks and garbage collection is probably the wrong (but a damn clever) idea.
mcc
in reply to Andy Jones • • •andreasdotorg
in reply to mcc • • •William
in reply to andreasdotorg • • •@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks and let us not forget what happens in a manual environment when you free a huge quantity of data in one batch, eg delete a large dictionary or whatever. Much longer pause time than an incremental GC.
Though one assumes you don't do that in a time-critical place 😀
William
in reply to William • • •@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks the memory safety in rust is awesome, except they insisted on building smart pointers (Box etc) on top of it for half-assed reference-counting memory management, though the last 30 years tells us that's not good enough.
Automated memory management requires a global not local (per pointer) view of liveness.
I want to see rust with real GC 😀
Zorro Notorious MEB 😡
in reply to William • • •@phenidone @andreasdotorg @mcc @andy_twosticks
My most recent disappointment with garbage collection involves R and `tidyverse` pipes on some large-ish transit data in an 8 GB laptop. By breaking the pipe chains into single steps and forcing a garbage collect after each step I was able to run it.
#RStats
Zorro Notorious MEB 😡
in reply to Zorro Notorious MEB 😡 • • •After that I
1. Upgraded the laptop to 32 GB, and
2. Rewrote the code using `data.table`, which can do the heavy lifting in place, rather that having multiple copies of large tables lying around.
#RStats
Zorro Notorious MEB 😡
in reply to Zorro Notorious MEB 😡 • • •@phenidone @andreasdotorg @mcc @andy_twosticks
Laziness is not always a virtue, especially in large-scale scientific computing where getting bounds on resource usage during the software engineering process is fairly easy (compared to, say a compiler or a theorem prover).
andreasdotorg
in reply to Zorro Notorious MEB 😡 • • •William
in reply to andreasdotorg • • •@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks "laziness" is also a term usually used to paper over macho Calvinist attitudes to programming, ie The Programmer Must Do It All, with a corollary of The Programmer Is Infallible.
We're writing software so we automate things. GC is automation, and it gets rid of several whole bug classes arising from the Infallible Programmer fallacy.
William
in reply to William • • •As soon as you reject the concept of automation for your own software, you either admit to writing code with memory leaks or you need to build a bad and ad-hoc substitute for GC inside your application, and oh look, here comes yet another implementation of reference-counting smart pointers.
William
in reply to William • • •So currently we seem to have these flavours of language:
1) free for all, go write you a bug (C)
2) static (compile time) automation of (some) object lifetime (C++ and Rust)
3) static analysis of lifetime, plus static bounds on concurrent access (Rust)
4) dynamic detection of lifetime and explicit dynamic access controls (Java etc) but no static borrow checks
William
in reply to William • • •@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks
IMHO we are sorely missing the ultimate combination of static lifetime analysis and borrow checking, with a modern/complete/incremental GC for the corner cases that a static checker cannot infer.
Basically, Rust with GC instead of smart pointers.
Yes I know I just made everyone angry but really it is for the better 😀
William
in reply to William • • •@andreasdotorg @mcc @AlgoCompSynth @andy_twosticks
Rust is kind of halfway there: it has mutexes (runtime access controls) because nobody is insane enough to claim that a static access control checker can work for all cases in a concurrent environment.
It just needs to make the next step and realize that runtime lifetime analysis is also required 😀
Zorro Notorious MEB 😡
in reply to William • • •@phenidone @andreasdotorg @mcc @andy_twosticks
If I understand the motivation for the design choices the Rust team made, it was to make "system programming" - presumably compilers / interpreters, operating systems, webservers, databases, browsers, etc. - easier to get right on a successful compile without sacrificing performance.
Zorro Notorious MEB 😡
in reply to Zorro Notorious MEB 😡 • • •@phenidone @andreasdotorg @mcc @andy_twosticks
Of that lot I've only done operating system programming, and that was so long ago that doing it in assembly was still the norm. 😀 If I were writing an OS today I'd do it in Rust. Case closed.
Operating systems don't have time for garbage collection. They don't even have time for floating-point computation. But they do need dynamic memory allocation and concurrency, and Rust is designed so the compiler saves the programmer time.
William
in reply to Zorro Notorious MEB 😡 • • •@AlgoCompSynth @andreasdotorg @mcc @andy_twosticks
Absolute nonsense.
If you have time to call free() or delete[] then you have time for the GC to do its thing.
William
in reply to William • • •@AlgoCompSynth @andreasdotorg @mcc @andy_twosticks also we are not running on 6502 and 68000 anymore. Cache locality is *critical* to performance, and you can often get measurable speedups using a compacting GC.
Admittedly the concept of "my data can move" is terrifying to people who were raised on C 😀 and there are terrible corner cases.
But you need to not think of GC as having only performance cost.
Devine Lu Linvega
in reply to William • • •Andy Jones
in reply to Devine Lu Linvega • • •nomand
in reply to Devine Lu Linvega • • •Devine Lu Linvega
in reply to nomand • • •very much
edit: To be clear, Uxntal hasn't changed. It's the same language as it was, but writing type inference reveals its hidden intricacies, similarly to how writing a BNF notation for a language might also.
Devine Lu Linvega
Unknown parent • • •Checking them is not too difficult, at the moment I add their stack-effect to the top of the fall-through and it seems to work for most cases. I'm trying to find a case where I can break out, but so far so good.
To be clear, the function does return, but it returns outside of its own scope.
example: https://git.sr.ht/~rabbits/left/tree/main/item/src/left.tal#L492
Functions that don't return like threads and vectors, have their own special type.
~rabbits/left: src/left.tal - sourcehut git
git.sr.ht