[HN Gopher] Counterexamples in Type Systems: programs that crash... ___________________________________________________________________ Counterexamples in Type Systems: programs that crash, segfault or explode (2021) Author : nequo Score : 175 points Date : 2023-06-06 14:51 UTC (8 hours ago) (HTM) web link (counterexamples.org) (TXT) w3m dump (counterexamples.org) | epolanski wrote: | This seems a super interesting read. | dvt wrote: | I think this is an interesting doc, but the argument that global | properties can be _guaranteed_ by a type system is false, so | there will _trivially_ be counterexamples of type systems. | | In fact, for any extensional type theory, we have the interesting | result that type inhabitation is undecideable. Further, when | looking at intersection types, there's also a theory saying | they're undecideable, and many more edge cases which I can't | remember. So the result is that we have a lot of "patching" in | compilers or runtimes that try to fill some of these holes, but | that's to be expected. | eimrine wrote: | Are there any reasons why searching Lisp word does not give any | result? Possible reasons: its type system is uncrashable, its | type system is as easy to crash as C program (I am too beginner | to know which is true). | Jtsummers wrote: | Probably for the same rationale they provided to exclude Python | from examination: | | > Python's type system: Dynamic languages like Python do local | type checks to establish global safety properties. However, the | type checks are not done purely on the program's source code | before running it, but examine the actual runtime inputs as | well. | shadowgovt wrote: | Interestingly, common lisp _does_ allow one to write unsound | programs intentionally. The `the` special operator | (http://clhs.lisp.se/Body/s_the.htm#the) declares that the | form in the second position _is_ of the type specified by the | first position. You can imagine that this allows the runtime | to crash early if the type is wrong, and you 'd be right... | But depending on the compiler you use, it _also_ allows for | the creation of unsound programs because you can set your | flags such that the compiler uses the presence of `the` to | make assumptions on the underlying types, letting the program | evaluate faster by throwing out some runtime type checks. | tmtvl wrote: | Ah yes, good old (declaim (optimize (safety | 0))) | mzs wrote: | oh my, hadn't known about this yet - 8 years and still unsolved: | https://github.com/rust-lang/rust/issues/25860 | weinzierl wrote: | Me too, is there a list of soundness holes in Rust anywhere? | | Also, if anyone has read the book, are there any interesting | Rust counterexamples? | nequo wrote: | Their issue tracker has a label for soundness holes: | | https://github.com/rust-lang/rust/labels/I-unsound | Taywee wrote: | Not a counterexample of the type system of Rust itself, but | this one with LLVM following C and C++ definitions of "side- | effects" is interesting: | https://counterexamples.org/eventually-nothing.html | [deleted] | ReleaseCandidat wrote: | Don't know what's interesting for you, but this is definitly | interesting: https://counterexamples.org/eventually- | nothing.html I've also found these | https://counterexamples.org/nearly-universal.html | https://counterexamples.org/selfishness.html | dataangel wrote: | I love this | afc wrote: | Why disqualify languages (like Python) simply because they | execute type checks dynamically? You could as well try to find | programs in these languages that crash (without containing any | issues that the language's dynamic type system detects at any | point, before the crash). | dtech wrote: | Because the definition of soundness is that if a program | typechecks it does not crash at runtime. This is a collection | of unsound programs that syill typecheck. | | Since there is no difference in Python and other untyped | languages between a potential typechecking stage and runtime | the definition is meaningless for them. | Jtsummers wrote: | Because it isn't appropriate to their objective: | | > It's intended as a resource for researchers, designers and | implementors of _static type systems_ , as well as programmers | interested in how type systems fit together (or don't). | [emphasis added] | | Change the objective, and dynamic type systems would be | appropriate. | z3t4 wrote: | Dynamic type languages usually have a very strong type system - | that makes it impossible to cause a type error. | lmm wrote: | What Python has literally isn't a type system; expressions in | Python don't have (the thing that Python calls) types, only | values do. So it wouldn't even be possible to do any of the | stuff this page is doing in Python. | kelnos wrote: | One thing that wasn't always clear to me: how many of these | examples crash due to bugs in the compiler/verifier, and how many | because the type system is actually unsound? | | Sometimes it _is_ mentioned; a Rust example and a Java example | were fixed years ago. So it seems... a little unfair? Obviously | all software has bugs; compilers are no exception. Examples where | the type system itself is unsound, and can 't be fixed without a | redesign, are IMO the only interesting ones. | blueberry87 wrote: | The point of this website isn't to mock software that has bugs | - it's to show pitfalls that have been fallen into before, and | could be fallen into again. If popular languages have | encountered them in the past, and fixed them, why not document | it? Helps people in the future. Sure, actual examples of pure | unsoundness _are_ more interesting, but creating unsoundness in | what should be a sound system is also useful to implementers of | these sorts of systems. | awinter-py wrote: | ugh first time I touched a haskell codebase it was crashing in | prod and nobody knew why | | real 'this never happens' energy | kccqzy wrote: | There's a big difference between crashing as in segfaults and | crashing as in I should have handled an exception but I chose | not to. I can trigger a crash by dividing by zero and not | handling it in almost any language. | | "Nobody knew why" could mean bad code, communication breakdown | or a host of things. You can make code puzzling in any | language. | suntipa wrote: | Lazy evaluation also implies that Haskell programs can crash | _based on their input_. That doesn 't imply big input, simply | that the input caused a space leak the author hadn't | considered. | | Try selling that to your boss who runs a mission-critical | app. | awinter-py wrote: | yes but haskell code is inherently puzzling and you are | supposed to get safety in exchange | nequo wrote: | What turned out to be the reason for the crashes in | production? | awinter-py wrote: | unknown | Konohamaru wrote: | I don't think there's a truly safe programming language. When I | was an undergraduate talking to somebody at the C. S. department | (I was not a C. S. student, but I talked with many C. S. | students) somebody there said that the risk of segfaults in C and | Java, when the program approaches hundreds of kloc, are about | equal. It's only in small, ungeneralizable programs where Java's | GC guarantees safety. | | Some people know how to manage memory and others don't. If you | know how to manage memory, even C is a safe language. If you | don't, not even the most formally-verified garbage-collected | language can save you. | ThereIsNoWorry wrote: | That's one of those misguided deep sounding statements that are | based in a fundamental lack of knowledge. What you, or this guy | at the CS department, said is completely bullshit, evidenced by | simple statistics of memory safety in languages. There is a | reason many big companies are adopting Rust, and it's not just | because "they feel like it" or they lack coders that "can | program in C". E.g. take a look at: | https://security.googleblog.com/2022/12/memory-safe-language... | Konohamaru wrote: | Rust works because the Rust type system and development | environment are tutors. They train up the developer like | magic nannies until they learn how to correctly manage | memory. | | So the power of Rust comes from the the cooperation of the | developer with the compiler and development environment | willing to work through their severe instruction. | | Developers in general unwilling to learn how to manage memory | walk away from Rust based devteams. | ThereIsNoWorry wrote: | Ok, there's still Java, Kotlin, Go and other memory safe | languages in the sense of that they are statistically way | less likely to have any memory related bugs compared to C, | C++ or similar low-level no GC, no reference counting | languages and thus the original argument of "good | developers" not doing memory related bugs as well as "Java | is as unsafe as C after a certain size" is utter bullshit. | Taywee wrote: | > I don't think there's a truly safe programming language. | | This is correct, technically, but you can achieve really high | assurances of safety. "safe" is not a binary, but a spectrum. | | The rest of the comment is patently false. It's actually close | to the opposite of reality. The stricter the type system, the | smaller the risk of unexpected behavior. Very very smart people | who "know how to manage memory" use C and introduce memory | errors very often. It's actually only in small, ungeneralizable | programs where weaker type systems _don 't_ matter. | ryukoposting wrote: | I'm a firmware engineer. The languages I use most frequently | for professional purposes are C and Rust. C is less "safe" than | Rust, in the sense that a larger share of C code is susceptible | to subtle footguns. Sure, if you poke at edge cases and fill | your code with unsafe blocks, Rust will do bad things too. To | me, this seems like a reasonable way of thinking about safety: | it's all relative, and it's all context-dependent. | | The conversation about language "safety" always leads to a | bunch of goalpost-moving. Is a language with a safe type system | still safe if its runtime is buggy? What if the OS/kernel has a | bug? What if the CPU has a bug? How about anomalies in I/O | hardware? Keep going down the rabbit hole, and you'll | eventually reach the conclusion that all software is extremely | fragile and could explode into a million pieces if a single | cosmic ray goes the wrong way. Thinking about safety in an | absolute sense isn't productive. | | As an aside, your CS buddies told you a bunch of nonsense. | jnwatson wrote: | At Google, that's definitely not true. Our C code crashes way | more often than our Java code. | | Memory management is harder than just remembering to free. It | requires a deep understanding of ownership, lifetimes, and | threading. That is hard at scale unless it is built into the | language. | marcosdumay wrote: | It's not the GC that guarantees safety. It's the encapsulation | of every memory access inside a safe interface in the | language's semantics. All the GC does is to make it possible to | create the most popular interfaces over a finite memory. | | And yeah, any bug on the interface or its implementation will | lead to unsafe memory usage. | | But anyway, no, if you make an interface where it's impossible | to get memory corruption, you won't get memory corruption. It | doesn't matter if the most inapt programmer on the world uses | it. And the idea that people can manually manage memory on | programs that are hundreds of megabytes large and created by | many developers (or a single one at many different times) is | about as wrong as the first part. | nerdponx wrote: | I've never encountered a segfault in Python that wasn't caused | by interacting with C code. Is that claim even true about Java? | unless it's a bug in the JVM itself, I'd be really really | surprised to see an actual memory-related error arise from | user-written code in any popular GCed language. | norir wrote: | Can confirm I've only gotten the jvm to segfault when writing | jni code -- never when writing vanilla java. To be generous | to the OP though, perhaps the person who made the original | comment was trying to write system code in java with lots of | jni to access syscalls, or perhaps earlier versions of the | jvm were less stable. The first jvm I ever used was 6, so I | can't personally speak to earlier version. | lmm wrote: | I've found two segfaults in a 10+ year Java (well, actually | mostly Scala) career (both known JVM bugs). It's rare, but | possible. | nradov wrote: | Are you referring to the programming language, or the compiler | and runtime environment necessary to execute the code? The Java | Language Specification doesn't provide any strong guarantees of | "safety". For example, it's certainly possible to write Java | code with heap memory leaks or stack overflows. And I have run | into multiple defects with the Oracle JVM that caused segfaults | when executing certain code (although to Oracle's credit, their | JVM is generally one of the highest quality and most reliable | pieces of large platform software ever created). | tester756 wrote: | Oh jezz, anecdotes from people from academy, please. | | >Some people know how to manage memory and others don't. If you | know how to manage memory, even C is a safe language. If you | don't, not even the most formally-verified garbage-collected | language can save you. | | Who knows how to manage memory then? | | Windows engineers? Chromium engineers? Linux engineers? | | all of them have history of failing at this, stop with this | mindset. | s_gourichon wrote: | > Welcome to Counterexamples in Type Systems, a compendium of | horrible programs that crash, segfault or otherwise explode. | | Many interesting quirks in type systems, surprising interference | between separately innocuous type system features, but don't | expect too many explosions. | | Indeed, many of the tricks are years old (e.g., 2006) and are | fixed in current versions of the language (or even are research | paper involving experimental systems that were never released, | e.g. Privacy violation in C# doesn't even use a syntax that | released C# compilers use). | | Mutable matching in Ocaml can be reproduced with ocaml 4.13, | still, and cause a segfault. | kazinator wrote: | Regarding Mutable Matching, that can be a documented feature. | Programmers perpetrating mutation in pattern guards probably | expect a certain behavior, like that patterns are evaluated from | left to right, and so patterns after the mutation will capture | its result. If that is documented and reliable, then changing it | breaks valid code. | | People who don't like it should avoid mutation. | | I.e. the following requirement does not really compute: "I want | to mutate inside a multi-case pattern, yet the pattern matching | mechanism must itself refer to an immutable, private snapshot of | the entire object, or behave as if that were the case." | | The requirement for "soundness" there really doesn't make sense; | the programmer has chosen to value mutation over soundness. | less_less wrote: | Soundness means that mutable matching doesn't break the type | system. It's fine for the behavior to be well-defined and | documented but unintuitive. But in a "safe" language, mutation | during a pattern match shouldn't allow you to bitcast an int | into a function and then call it (which will segfault or | worse). | kazinator wrote: | Yes; if one pattern matching case infers that some field of | an object is a function, but that is mutated to int, another | case cannot keep going with that assumption and generate code | where the int is treated a function. | | That would almost seem like a downstream compiler problem. If | the pattern matching expander emits straightforward code, | similar to what you would write by hand, then it would have | to be the compiler doing the wrong thing there, like doing | type inference without noticing that some location whose type | was inferred was replaced by a differently typed object. | | If pattern matching itself generates type hints for the | compiler, then the fault could lie there. | rob74 wrote: | Looks like the requirements for a "type system" have increased | since I last looked - according to the article, a type system | only deserves that name if it prevents use-after-free errors, | memory corruption etc. etc. And here was I thinking that every | strongly typed language already has a type system (a more or less | sound one, but a type system)? Ok, TBF they mention that they are | using a "fairly narrow" (re)definition of the term... | cvoss wrote: | > according to the article, a type system only deserves that | name if it prevents use-after-free errors, memory corruption | etc. etc. | | I mean, you are hiding a lot of possibilities in "etc. etc.". | So is the article, when it says "and the like" in the sentence | you're referring to. The kinds of things that belong in this | list are described as "generally some sort of safety property." | That's a big big list of things. It's not a particularly strict | or narrow definition of type system, IMO. | | Take C. What does it mean when C's type system says a variable | "x" has type "int"? Practically, it means the compiler knows | how many bytes (let's say 4) to reserve on the stack for x. But | what if the program, during the course of execution, tries to | write an 8-byte piece of data to x? The language is broken if | that can occur because the compiler was not justified in | reserving only 4 bytes for x. So, part and parcel of C's type | system is a global safety property: It promises, among many | other things, that at runtime no assignment will ever occur to | an int-typed variable unless the assignment payload is 4 bytes. | | So this is exactly what the article is talking about. Local | rules (e.g., "int x = y" is well-typed if y has type int) | working together to guarantee a global safety property (no type | mismatches can occur at runtime). | | The failure of a type system to do this properly is a failure | at being a type system. And indeed, since C has undefined | behavior, it's type system falls apart immediately. It's just | not even interesting to consider enumerating the ways it can be | broken. | | The type systems considered by this article are ostensibly | supposed to not be broken the way C's is. That's what makes the | counterexamples of this article so interesting. | avgcorrection wrote: | There's a difference between a type system and a type system | that is sound. | | > according to the article, a type system only deserves that | name if it prevents use-after-free errors, memory corruption | etc. etc. | | Soundness is a technical term. | | Things can get pretty weird if you allow memory corruption. | Some languages say that certain things are Undefined Behavior. | Imagine if a logician said the following: | | - Here is my sound and complete logic | | - By the way, some valid formulas will give you Undefined | Behavior and I don't care what happens in those cases | | That would be pretty wild. | DaiPlusPlus wrote: | > Things can get pretty weird if you allow memory corruption. | Some languages say that certain things are Undefined Behavior | | UB in C allows for a lot more than just memory corruption | though (c.f.: nasal demons). Also, what about alternatives to | UB, such as requiring a compiler error and/or runtime fatal | error? | stonemetal12 wrote: | If we consider a program a state machine, then a sound type | system is one that rules out all operations for which the | next state is undefined. So Null pointer dereference is | sound in Java. The next state is well defined even if it is | just throw a NPE. In C it is not, because there is no well | defined next state. | mrkeen wrote: | > a type system only deserves that name if it prevents use- | after-free errors | | Or another way to look at it: if I tell you you're holding an | Integer, and when you try to use it in addition, it explodes, | was I really justified in telling you you were holding an | Integer? | rwmj wrote: | That's kind of a bad example because adding integers can | overflow (in some languages). | shadowgovt wrote: | Depending on how you turn your head and squint, overflow is | still well-defined: if I add a to b and it overflows to c, | it still overflows to the _same_ c every time. That means | addition is sound in that architecture, it just has | surprising consequences and some properties one would | expect naively to hold for positive-integer arithmetic don | 't hold for the computer addition operation (such as c > a | && c > b for all a > 0 and b > 0). | Sharlin wrote: | From the specific perspective of the article, C++'s type system | is uninteresting because it's so trivially and fundamentally | unsound. It's easy to come up with a single line of C++ (eg. | overflowing a signed int) that works as a counterexample. | Languages whose type systems make stronger guarantees you have | to make an effort to break. | | A type system that allows undefined behavior is equivalent to a | logic system that allows proving a falsehood, and _ex falso | quodlibet_ - from a falsehood you can prove anything. | kelnos wrote: | You are conflating two different (but related) concepts. The | requirements for type system to be a type system have not | changed. Neither have the requirements for soundness. Most | mainstream languages have tacitly accepted unsoundness for | decades, but newer languages aim to have type systems with | fewer and fewer unsound rough edges. | | For example, I would consider Java to be a strongly-typed | language, but it has quite a few unsoundness issues that can | come up in regular, non-contrived code. Scala's type system is | stronger and more full-featured, but it's not clear to me that | it's significantly more sound. Rust, perhaps, has a (strong) | type system with fewer soundness issues than both Java and | Scala, but some issues do exist. | | C and C++ have comparatively weak type systems (though C++'s is | certainly stronger than C's), and their type systems have quite | a few soundness issues, many of which that can be exposed via | simple one-liners. | | Also consider that soundness issues are not all created equal. | I would much rather see a ClassCastException at runtime in a | Java or Scala program, than see memory corruption (with | possible security or data-integrity consequences) in a "valid" | C/C++ program when I misuse memory designated as one type, as | another. Certainly the best case would be a compiler that | wouldn't allow it in the first place, but the Java/Scala | example is nowhere near as bad as the C/C++ example. | lmm wrote: | What does it even mean for a program to be well-typed if that | program has "use-after-free errors, memory corruption etc. | etc."? A program with C-style undefined behaviour could ipso | facto fail with a type error on any given line. | kccqzy wrote: | > more or less sound | | There isn't more or less sound. There's really only sound or | not. | AnimalMuppet wrote: | Then there's really only "not". | | If you require perfect, 100% soundness in all circumstances, | then _nothing_ is sound. | | (Probably. We have things that we thought were sound, and | later proved were not, so if you start with the list of | things now that have _no_ known holes, that 's the upper | limit of things that are possibly sound, modulo future | holes.) | | If you seriously try for perfection, you can sometimes get | pretty close. But if you insist on perfection or nothing, you | usually get nothing. | salawat wrote: | >If you require perfect, 100% soundness in all | circumstances, then nothing is sound. | | Soundness in logic requires both valid form, and _reasoning | from true premises_. | staunton wrote: | The problem is that _in practice_ there is absolutely | never any way to be 100% sure that the form is valid, the | reasoning is correct, or that the premises are true. You | can get pretty close to 100% but there might always be | cases where you 're not close enough "for _all_ practical | purposes ". | staunton wrote: | We have cosmical background events which cannot be shielded | 100% and also cannot be predicted. This (among thousands of | other reasons) means that you can _never_ prove 100% what any | given program will do on a computer. | | Indeed, it's impossible to _prove_ absolutely any fact about | a real physical system. You prove things about abstract | mathematical objects. Such a proof may be useful in practice | when the assumptions you made for the proof are satisfied to | a sufficient degree in a sufficient number of cases. Whether | this is the case or not is ultimately a matter of judgement | (and data, for which you have to use judgement in collecting | /interpreting it, and data, for which...) | | By the way, the paper you're using to write proofs in | mathematical logic is a physical system. | kccqzy wrote: | You are missing the point. This article isn't talking about | a real physical system, we _are_ talking about abstract | mathematical objects. The study of type system is to | formalize the type system so they can be studied using | logic alone. That 's why there is the matter with | soundness, the topic of this thread. Soundness is abstract, | not physical. | | (The endless appeal to practicality and physicality is both | tiring and irrelevant. Circles as a shape don't exist in | the real world because you can't use physical objects to | create a circle; at some point, perhaps at the level of | atoms, the perfect smoothness of the ideal circle breaks | down into discrete atoms. So circles don't exist. Does it | bother me? No. Does it bother you? Evidently it does.) | Spivak wrote: | I find it funny that the author excludes Python's type system | because python is strongly typed but the nature of runtime | checking means you can't blow up your program. | cryptonector wrote: | That's not remotely a fair characterization of what TFA says | about Python: | | > This is intentionally a fairly narrow definition. Some | examples of things that are not "type systems": | | > Python's type system: Dynamic languages like Python do local | type checks to establish global safety properties. However, the | type checks are not done purely on the program's source code | before running it, but examine the actual runtime inputs as | well. | | It does not say "python is strongly typed but [...]", not even | "python is strongly typed". The words "strong", "strongly", and | "strength" do not even appear. TFA says that Python being | dynamic means it is not type-checked at compilation time -- | that's practically the same as saying the opposite of "python | is strongly typed" for most people's intended meaning of | "strongly typed". | Jtsummers wrote: | > TFA says that Python being dynamic means it is not type- | checked at compilation time -- that's practically the same as | saying the opposite of "python is strongly typed" for most | people's intended meaning of "strongly typed". | | Strong typing is a weak concept (pun intended). The most | useful meaning is, roughly, no or little automatic type | coercion (so a numeric tower might still be "strong", but | coercing a string "1" into the number 1 is "weak"; `"1" + 1` | => `"2"`). Anyone who uses "strong typing" as synonymous with | "static typing" is making a very silly mistake. | cryptonector wrote: | I'm trying to understand what GP meant by "strong" here. | TFA doesn't say anything about "strength" of typing. | paulddraper wrote: | Still looking for the explosions... | masklinn wrote: | That's because TorgueLang is TBA, but don't worry it'll be an | explosions-based language. | armchairhacker wrote: | Fun fact: even theorem provers have counterexamples | | - Breaking Badfny: | https://www.reddit.com/r/Coq/comments/x4d31y/breaking_badfny... | | - Falso (Coq): https://github.com/clarus/falso | | - Coq critical bugs (some of these mention potential ways to | prove false): | https://github.com/coq/coq/blob/master/dev/doc/critical-bugs | | (You can also get the theorem prover itself to hang or crash; if | you work with theorem provers often, you'll even do this | unintentionally, many times!) | gnulinux wrote: | Not just simple counterexamples (i.e. programming "bugs"), some | theorem provers have systematic bugs that were discovered later | and required programming language change because people | building it weren't sure how to fix it, mathematically | speaking. | | For example, in Agda, there are two ways to create coinductive | types. The most liberal and useful one uses a technique called | "Sized Types". Sized Types are types where you annotate each | type with a compile type upperbound "size" which allows | compiler to prove a given coinductive computation on this | object will terminate. You can image a conductive list "List T | i" where "i" is a "Size Type". Ultimately, the compiler | implements this using a mix of lazy evaluation and bookkeeping | upperbounds using natural numbers. | | Originally, this was part of the "safe" subset of the language. | Meaning, you can write Agda code using Sized Types, and Agda | compiler claims the subset of the language you use is sound. | This means you cannot prove inconsistencies. Here comes this | "bug" which showed otherwise: | https://github.com/agda/agda/issues/1201 Since 2015 Agda | developers have been working on ways to mitigate this problem. | Finding no such solution, they eventually decided in May 2021 | to remove Sized Types from the "safe" subset of the language: | https://github.com/agda/agda/pull/5354 | nerdponx wrote: | It's probably worth distinguishing between "compiler bugs" | and "fundamental theoretical problems". From what I've seen | of Idris 2 development, sometimes what looks like the former | turns out to be the latter. But what I find really cool is | that the theoretical problems are not necessarily unsolvable, | and there seems to be a steady stream of new theoretical | results that find their way into compilers. So even if we are | a very long way off from these languages gaining wide | adoption, it's exciting to see that progress is in fact being | made, even if it's slow. | Analemma_ wrote: | This is not my area of expertise, but I clicked around those | Agda bugs with some interest, and it seems like all those | problems are stemming from the fact that they defined inf < | inf. A couple people mentioned addressing the issue by | getting rid of that, and others objected that it would cause | more problems than it solved. What are those problems? Why is | inf < inf? | HappyPanacea wrote: | This is also not my area of expertise, but considering they | are using sized types to prove termination through well- | foundness so they are probably suppose to be ordinals where | we can have o < o+1 but for some reasons they decide to | forgo to distinguish between everything larger than o and | denote it as inf. | | Edit: I found an explanation | https://ionathan.ch/2021/08/04/sized-types.html | mananaysiempre wrote: | The tongue-in-cheek MOTD of the Agda IRC channel outright says | "We last proved false at ...". | | Of course, Agda is somewhat unusual because they are kind of | making up the (very strong) logical theory as they go along | instead of having a fixed core logic they could dump proofs in | for double-checking, like Coq. On the flip side, Agda actually | makes for a halfway usable programming language--unlike Coq. | nickdrozd wrote: | > You can also get the theorem prover itself to hang or crash; | if you work with theorem provers often, you'll even do this | unintentionally, many times! | | Proving something false is a grave sin for a prover. On the | other hand, failing to prove something true is not only | forgivable, but inevitable as per the incompleteness theorem. | While ideally this failure would presented in terms of a nice | error message, crashes are preferable to unsoundness. Crashes | can even be deliberately induced as a defensive measure: | https://hal.science/hal-04096390/document | CHY872 wrote: | It really depends on how automated the prover is, this is | kind of like reinforcement learning optimising something | unintentionally. Theorem prover bugs are problematic if | relied upon, but most of the bugs folks cite are only usable | in very strange circumstances, and most practitioners will | not see their results invalidated by such a bug. E.g. iirc | falso required a type with more than 256 variants. If you | don't have one of those, it won't affect you! | | Essentially, you fix the bug, re-run your hol or whatever, | and hope your theorem is still true. | | Obviously this only applies to bugs in the implementation as | opposed to an unsound logic. | shadowgovt wrote: | Very interesting read. I had to chuckle a bit that they exclude | C++ examples because the C++ type system doesn't even pretend to | guarantee the behavior of the program is defined. | staunton wrote: | At least they don't pretend. On the other hand, they seriously | try to define _exactly which programs have defined bahavior_ | and to define behavior for those. (I 'm really not a fan of C++ | but I'll grant them this good effort at least) | | As of 2023, anyone whose language claims to guarantee behavior | of all programs is either kidding themselves or will never have | a user base to speak of for their language. ___________________________________________________________________ (page generated 2023-06-06 23:00 UTC)