companion_cube changed the topic of #ocaml to: Discussion about the OCaml programming language | http://www.ocaml.org | OCaml 5.2.0 released: https://ocaml.org/releases/5.2.0 | Try OCaml in your browser: https://try.ocamlpro.com | Public channel logs at https://libera.irclog.whitequark.org/ocaml/
<discocaml> <contificate> they're also one shot delimited continuations which isn't a major limitation, but clearly the cost savings are important to things that are actually scheduling tasks that way
<discocaml> <contificate> what's kind of bizarre to me - and maybe I'm alone in this perception - but, generally, I watched a bunch of people who never cared about delimited control of any kind become obsessed with effects and handlers overnight
<discocaml> <ape_logic> well, they're probably concerned with the problems they see them as potentially solving rather than the mechanisms themselves
<companion_cube> I had my phase about effects but I went back to just seeing them as a tool to get async
<discocaml> <contificate> I think a lot of it is hype around buzzwording
<discocaml> <ape_logic> I really do not care what approach is used provided it gives errors captured within the type system
<discocaml> <ape_logic> I think Rust's approach is ok but using an enum/adt as the return type for errors makes composing them annoying
<discocaml> <contificate> all this stuff is like a different interface for stackful coroutines, ignoring any static effect safety that OCaml does not yet have
<discocaml> <contificate> I used to enjoy Java's `throws` specifications on exception-raising methods
<discocaml> <contificate> but more often than not you'd have catch-all cases that do nothing except print a backtrace
<discocaml> <contificate> exceptions are meant to be for exceptional cases which can often not be mitigated or recovered from
<companion_cube> Or just, exit or cancel the fiber
<companion_cube> If result was as easy as in rust I'd use it more pervasively, but well
<discocaml> <ape_logic> I guess.. but if they're only ever exceptional, what do we do if someone divides by zero, or tries to read from a closed socket?
<discocaml> <contificate> divide by zero should just be zero
<discocaml> <contificate> and I stand by this
<discocaml> <contificate> literally don't care
<discocaml> <ape_logic> me against the world type stance
<discocaml> <ape_logic> I respect it
<discocaml> <contificate> nah this is a fairly popular viewpoint
<discocaml> <ape_logic> seriously? I've never heard it before
<discocaml> <contificate> where I get odd looks is when I say "at the processor level"
<companion_cube> 0 is the new nan
Everything has quit [Quit: leaving]
<companion_cube> Reading from a closed socket could return a result but then most of your io path becomes monadic again, sad
Everything has joined #ocaml
eilvelia has quit [Quit: eilvelia]
<Soni> honestly, most of the issues with exceptions would be solved by being explicit about *where they can be thrown*
<Soni> (not checked exceptions. not where they can be caught. simply where they can be thrown. if they're thrown outside of allowed contexts? turn them into something that can't - or at least shouldn't - be caught)
YuGiOhJCJ has joined #ocaml
<Soni> if your API says it throws X when you do X, then it shouldn't throw X when you do Y.
<Soni> (and if it attempts to throw X anyway when you do Y, the language should convert that into something that can't be caught, at runtime. kinda like an assert or something.)
<companion_cube> Well, the day we get effect types
malte has joined #ocaml
Haudegen has quit [Quit: Bin weg.]
<Soni> implicit Result::unwrap() of explicitly declared exception types, basically
<Soni> (which is kinda like the opposite of checked exceptions in some ways)
Tuplanolla has quit [Quit: Leaving.]
Everything has quit [Quit: leaving]
malte has quit [Remote host closed the connection]
malte has joined #ocaml
YuGiOhJCJ has quit [Ping timeout: 260 seconds]
chiselfuse has quit [Ping timeout: 260 seconds]
chiselfuse has joined #ocaml
YuGiOhJCJ has joined #ocaml
pi3ce_ has quit [Quit: https://quassel-irc.org - Chat comfortably. Anywhere.]
pi3ce has joined #ocaml
f[x] has quit [Remote host closed the connection]
szkl has quit [Quit: Connection closed for inactivity]
toastal has joined #ocaml
toastal has left #ocaml [#ocaml]
myrkraverk has quit [Ping timeout: 246 seconds]
pippijn_ has joined #ocaml
<dh`> erm, the point of checked exceptions is where they can be thrown
pippijn has quit [Ping timeout: 260 seconds]
bartholin has joined #ocaml
Serpent7776 has joined #ocaml
toastal has joined #ocaml
bartholin has quit [Quit: Leaving]
myrkraverk has joined #ocaml
Haudegen has joined #ocaml
zenes has joined #ocaml
zenes has quit [Changing host]
zenes has joined #ocaml
rgrinberg has joined #ocaml
rgrinberg has quit [Ping timeout: 252 seconds]
rgrinberg has joined #ocaml
contificate has joined #ocaml
zenes has quit [Ping timeout: 252 seconds]
toastal has left #ocaml [Disconnected: Hibernating too long]
<Soni> the point of checked exceptions is to make you handle them
<Soni> you can throw them anywhere you just need to force someone else to deal with it
<Soni> maybe we should just pull the python thread 1 sec
contificate has quit [Ping timeout: 256 seconds]
toastal has joined #ocaml
rgrinberg has quit [Quit: My Unrecognized Mac has gone to sleep. ZZZzzz…]
mange has quit [Quit: Zzz...]
YuGiOhJCJ has quit [Quit: YuGiOhJCJ]
<discocaml> <dinosaure> actually, we prefer the `Result` monad than exception in the mirage codebase. Exception are mainly used for `invalid_arg` (you give a bad argument) but if a process fails for wathever reason, we prefer a `result` type
<discocaml> <dinosaure> then, about the error type, we use a polymorphic variant for composability
<Soni> we think exceptions are misunderstood by programmers. our experience talking about exception-oriented programming has solidified that opinion.
Haudegen has quit [Quit: Bin weg.]
contificate has joined #ocaml
myrkraverk has quit [Read error: Connection reset by peer]
myrkraverk has joined #ocaml
gentauro has quit [Ping timeout: 264 seconds]
gentauro has joined #ocaml
contificate has quit [Quit: Client closed]
contificate has joined #ocaml
Haudegen has joined #ocaml
mbuf has joined #ocaml
toastal has quit [Ping timeout: 255 seconds]
f[x] has joined #ocaml
toastal has joined #ocaml
contificate has quit [Quit: Client closed]
myrkraverk_ has joined #ocaml
myrkraverk has quit [Read error: Connection reset by peer]
germ_ has quit [Remote host closed the connection]
germ_ has joined #ocaml
chiselfuse has quit [Ping timeout: 260 seconds]
chiselfuse has joined #ocaml
<discocaml> <ada2k> i think a good base rule is that if an error is immediately recoverable it shouldn’t be an exception
Haudegen has quit [Quit: Bin weg.]
<discocaml> <ada2k> breaking control flow is very useful, but even effects aren’t typed 😭
zenes has joined #ocaml
zenes has quit [Changing host]
zenes has joined #ocaml
<Soni> can you do something in ocaml where you uh
<Soni> well, can you create a function that takes a list of exceptions and a block, and runs the block and any of the listed exceptions get turned into something else (program exit? or maybe a new exception type, "uncaught"), but then you also get another function you can use within the block to create blocks where those exceptions *can* be thrown and will propagate out of the outer block as-is (instead of becoming "uncaught")?
<Soni> (see also that python thread)
<companion_cube> can't really do a list, but you can do a pattern match
<Soni> can you make it look somewhat like this, basically: https://discuss.python.org/t/better-way-to-deal-with-exceptions/70162/73
<Soni> because if so, maybe this would be worth experimenting with?
Haudegen has joined #ocaml
szkl has joined #ocaml
motherfsck has quit [Quit: quit]
mbuf has quit [Quit: Leaving]
motherfsck has joined #ocaml
<dh`> I don't understand what that's supposed to accomplish; seems like rearranging the deck chairs on the titanic
zenes has quit [Remote host closed the connection]
<dh`> if you really really want to throw the equivalent of an entirely uncheckable NullPointerException out of your own library and expect a user of the library to be able to catch it and have it mean anything...
<dh`> the best bet is probably to throw only SoniNullPointerException and at the top-level entry points to your library, which are hopefully few, catch all the SoniExceptions and rethrow them as standard ones
<dh`> otherwise you'll never get these unenforced checking blocks right
Anarchos has joined #ocaml
qrpnxz has joined #ocaml
Anarchos has quit [Quit: Vision[]: i've been blurred!]
bartholin has joined #ocaml
<Soni> dh`: the API contract blocks are more useful than you think, give them a try
<discocaml> <yosefalsuhaibani_53718> Hello! Question: How maintained/supported is the ocaml-option-musl,ocaml-option-static compiler options? I am trying to switch to building our release binaries from alpine to this option, and there are a few packages that fail to find C libraries on a fresh CI run.
Haudegen has quit [Quit: Bin weg.]
Haudegen has joined #ocaml
qrpnxz has quit [Quit: WeeChat 3.8]
qrpnxz has joined #ocaml
Stumpfenstiel has joined #ocaml
olle has joined #ocaml
olle has quit [Ping timeout: 252 seconds]
<dh`> soni: I doubt it, the only thing exceptions are really useful for is allowing applications to crash in application-specific ways
<dh`> they're too unstructured and there's no viable recovery scheme
<discocaml> <mbacarella> haha my view on exceptions is that they're segfaults that don't corrupt program state and let you decide if you want to keep continuing some arm of the application
<companion_cube> they only affect one thread, too, they're really not that bad
<Soni> they're useful for all sorts of things
mange has joined #ocaml
<Soni> if only you had language support for all of these things
<Soni> (which nobody does for some reason)
<companion_cube> it's hard to do typed exceptions well, you need non trivial type inference for functions
<companion_cube> cause you need List.map to be polymorphic over the exceptions of its first argument
<discocaml> <mbacarella> i thin the answer to not having typed exceptions is just "is this function doing failwith? no? it should return option or result instead obvioulsy"
<discocaml> <mbacarella> i think the answer to not having typed exceptions is just "is this function doing failwith? no? it should return option or result instead obviously"
<discocaml> <mbacarella> where failwith here means kind of fatal error
<discocaml> <mbacarella> that you catch at the top of your main loop and print out and then pretend never happened
<discocaml> <mbacarella> or abort whatever
<discocaml> <mbacarella> it'd be kind of cool to have a `noexcept` qualifier like C++ though I guess to guarantee no exceptions in this call tree
<companion_cube> is List.map `noexcept`? :p
<companion_cube> (I mean, maybe every expression can be noexcept or yesexcept but it's basically like an effect type system I think)
<discocaml> <mbacarella> only if `f` is :3
<discocaml> <mbacarella> i guess unlike C++, floating point exception is an actual exception in ocaml and much more annoying to guarantee
<discocaml> <mbacarella> i guess unlike C++, floating point exception is an actual exception in ocaml and much more annoying to guarantee that they can't happen
<discocaml> <mbacarella> hmm probably would play annoyingly with polymorphic compare
<companion_cube> hmm which float exception?
<companion_cube> oh yeah. `compare` can raise :
<companion_cube> :/
<sleepydog> huh, really?
<discocaml> <mbacarella> this is hard nevermind
<companion_cube> `compare ignore ignore`
<sleepydog> ah, comparing functions
<discocaml> <mbacarella> your program will raise SIGFPE if you divide by integer 0 actually
<discocaml> <mbacarella> your program will signal SIGFPE if you divide by integer 0 actually
<companion_cube> but that's not float :)
<discocaml> <mbacarella> 😭
<sleepydog> i thought floating point stuff returned NaN instead of raising
<companion_cube> then it's turned into an exception by OCaml, anyway
<companion_cube> yep
<discocaml> <._null._> In both OCaml and Python's design, exceptions are really a way towards alternate program flow, as far as I can tell
<companion_cube> among other things, yeah
<companion_cube> `End_of_file` is one of the examples of that
<sleepydog> there are exceptions like `Not_found` in the stdlib that you could argue should be within the range of the function
<companion_cube> the other thing is that exceptions in OCaml can be really fast
<discocaml> <mbacarella> ```ocaml
<discocaml> <mbacarella> match%bind Reader.read_line reader with
<discocaml> <mbacarella> | `Ok foo -> (* ... *)
<discocaml> <mbacarella> | `Eof -> (* ... *)
<discocaml> <mbacarella> ```
<discocaml> <mbacarella> final answer
<companion_cube> this allocates a polymorphic variant :)
<companion_cube> that said I think for a realine function it's fine to return an option
<sleepydog> how come?
<discocaml> <mbacarella> when people say exceptions are fast in ocaml i don't really understand what makes exceptions slow in other langs/runtimes. you just... unwind the stack and drop references and jump to the handler no?
<discocaml> <mbacarella> how else could you do it?
<Soni> you generate a stack trace, then unwind the stack and drop references and whatnot
<discocaml> <mbacarella> oh I see. stack traces are disabled by default in ocaml
<Soni> (this could be optimized to jump to the handler *without* unwinding the stack, and delay stack trace initialization until you run out of stack (forced to unwind) or... some other condition where you'd need to save the stack trace (exception escapes stack?))
<companion_cube> you barely unwind the stack, iirc there's a register pointing directly to the nearest handler
<companion_cube> in the fast case it's really super cheap
<companion_cube> in C++ for example, you have to unwind each frame to run destructors, etc. it's a lot more work
<Soni> anyway nothing a JIT can't handle
<companion_cube> and `raise_notrace` doesn't use build a stack trace
<discocaml> <mbacarella> `raise e` should actually just be translated to a call to a closure that corresponds to the exception handler `with ... e ->` arm. the memory will probably get freed when you finish whatever project you were working on
<companion_cube> we discussed that with @contificate recently
<companion_cube> I don't think there's even a closure
<companion_cube> you directly jump to the nearest `with e -> …` and run the pattern match there
<discocaml> <mbacarella> huh. compiler is design is easy.
<Soni> surprisingly, error handling is fairly cheap in lua
<Soni> (out of all things)
<discocaml> <contificate> Yeah but there's a dynamic component to installing a handler, so there must be some kind of function pointer at the least being moved into somewhere when you install a handler.
<discocaml> <contificate> Same way that when you chase up fibers, you invoke all the handlers in case one has the effect case you want to handle
<Soni> (it's mostly just a function call overhead or two)
<Soni> but none of that really matters
<Soni> what matters is that we want a language that catches typos that throw API contract-relevant exceptions
Everything has joined #ocaml
<companion_cube> Do we know it's a function call??
<Soni> companion_cube: lua doesn't generate stack traces for every error. instead, it calls the error handler at the error location. (see: xpcall, and its relation to debug.traceback)
<Soni> and xpcall is generally how C functions call into lua so it's really no more expensive than a function call or two
f[x] has quit [Remote host closed the connection]
<discocaml> <mbacarella> the only places i'm aware of lua being used is in neovim and stuxnet
<discocaml> <mbacarella> what do you use it for? 😅
<Soni> we haven't used lua in a while tbh
Stumpfenstiel has quit [Quit: No Ping reply in 180 seconds.]
Stumpfenstiel has joined #ocaml
rgrinberg has joined #ocaml
Stumpfenstiel has quit [Ping timeout: 245 seconds]
Serpent7776 has quit [Ping timeout: 245 seconds]
<discocaml> <mbacarella> `[1797806.719383] ocamlc.opt[1495743]: segfault at 3 ip 000059f1339a4ad1 sp 000059f134f7fed0 error 4 in ocamlc.opt[59f133884000+35e000] likely on CPU 4 (core 16, socket 0)`
<discocaml> <mbacarella>
<discocaml> <mbacarella> i keep getting segfaults on `CPU 4 (core 16, socket 0)`
<discocaml> <mbacarella> think i have a problem here
<discocaml> <mbacarella> i'll just pass --jobs=1 to everything from now on until i refresh my workstation in *checks notes* 2 more years
bartholin has quit [Quit: Leaving]
<discocaml> <mbacarella> maybe I can just disable that one core
<companion_cube> Maybe you can tell that to your os scheduler?! Idk
Tuplanolla has joined #ocaml
<discocaml> <mbacarella> i'm kind of impressed that i can otherwise use my system until i try to install a bunch of ocaml packages in parallel
<discocaml> <mbacarella> i guess that explains random chrome crashes a few times a week
<discocaml> <mbacarella> claude suggests `echo 0 > /sys/devices/system/cpu/cpu4/online`
<discocaml> <mbacarella> hey that worked, cool
<sleepydog> might want to disable its ht sibling for good measure 😛
<discocaml> <mbacarella> also, god that was disturbing
<discocaml> <mbacarella> sleepydog: I have HT disabled
<sleepydog> oh, you have 16 real cores??
<discocaml> <mbacarella> yes, I'm on an i9-14900K
<discocaml> <mbacarella> they're great
<discocaml> <mbacarella> except for the part where a random cpu corrupts stuff
<sleepydog> nice
<sleepydog> I mean, nice to the core count, not the corruption, heh
<discocaml> <mbacarella> isn't there a google paper about this
<discocaml> <mbacarella> god that's awful. imagine how many wrong hashes a core like that can sneak in over its life
mange has quit [Ping timeout: 265 seconds]