Unions, program proofs and the Halting Problem

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Unions, program proofs and the Halting Problem

Post by Combuster »

Brendan wrote:However; despite your curse, I would've hoped you'd be intelligent enough to understand that learning something is always harder than not needing to learn something; and having to take something into account is always harder than not needing to take something into account.
Actually, I don't know them as unions at all. Tagged unions is just like a very-low-level way of describing enumerations with attached data. Untagged unions are pretty much a misfeature and are only meaningful for ugly_casting raw bytes to floats. So why not remove unions completely?

In fact, I tend to call them data types instead. That lecture was 9 years ago. The concept was so simple and effective I've missed it in all other languages since.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: The Mill: a new low-power, high-performance CPU design

Post by Rusky »

Brendan wrote:Buffer overflows; and not dangling, undefined, or null pointers?
The last three are included in the first category by those papers. Unless you think the last three have never caused a single vulnerability?
Brendan wrote:If a compiler tracks the ranges of values that are possible in each variable, those unsafe things end up being compile time errors.
You missed the part where I actually do think that's a good idea, ironically despite the fact that it makes the programmer learn more language features, unlike tagged unions/algebraic data types/enums which are conceptually as simple as integers for beginners- "this type can be 1 or 2 or 3 or..." "this type can be a Square or a Circle or...").
Brendan wrote:There is still one problem - the caller could ignore the returned status and end up using a null bounded pointer (and even if they don't, error handling ends up on the critical path). Let's fix that using "alternative exits":
So now you've just reinvented single-stack-frame extensions and/or continuations, neither of which are easy to implement efficiently, while an Option<T>/Either<T,Error>/etc type has the same benefits (the caller can't ignore the returned status), is conceptually simpler control-flow wise for beginners ("this can either give me a result or an error"), and can still be easily optimized to remove error handling from the critical path (through partial inlining).
Brendan wrote:This is a continuation of the same problem - the offset of Rect structure within the union is different for the enumeration's Recangle and Both, so you're forced to have an ugly switch/case thing inside "calcRectangleArea()".
So you don't actually want a union then.
Brendan wrote:If the compiler can determine that circle, rectangle and square are never used at the same time; then it can co-locate the structure members and the structure can be just as good as a union. If the programmer makes a minor change (e.g. so that rectangle and circle might be used at the same time) then with no additional changes whatsoever everything continues to work perfectly.
That sounds an awful lot like the compiler doing things behind your back, [url=http://forum.osdev.org/viewtopic.php?p=232051#p232051]which I thought you didn't like[url].

For someone who wants a programming language not to introduce too much to beginners, you sure like pointers. Empirically speaking that's one of the hardest things for beginners to learn.
embryo

Re: Unions, program proofs and the Halting Problem

Post by embryo »

Brendan wrote:Worst: No optimisation
Average: Programmer has to assist optimiser
Best: Programmer doesn't have to assist the optimiser
I think programmer must assist optimizer. Not always, but when performance is an issue. And compiler's goal is to make such assistance very seldom for the programmer.
Brendan wrote:Of course you're right - if a try to get it right and fail; then I can try to hide my failure behind pragmas/annotations later on.
Does it means you are trying to create your personal language first? I suppose it should be something like C. And C was Java's starting base, also. Are you creating better Java? :)
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: The Mill: a new low-power, high-performance CPU design

Post by Brendan »

Hi,
Rusky wrote:
Brendan wrote:There is still one problem - the caller could ignore the returned status and end up using a null bounded pointer (and even if they don't, error handling ends up on the critical path). Let's fix that using "alternative exits":
So now you've just reinvented single-stack-frame extensions and/or continuations, neither of which are easy to implement efficiently, while an Option<T>/Either<T,Error>/etc type has the same benefits (the caller can't ignore the returned status), is conceptually simpler control-flow wise for beginners ("this can either give me a result or an error"), and can still be easily optimized to remove error handling from the critical path (through partial inlining).
My "alternative exits" are extremely easy to implement. The alternative exit provided by the caller must be a label in the caller; and all the compiler does is insert a "mov [esp],???" instruction to change the function's return address before doing "ret". Of course if the function is inlined into another function then "return alternativeExit" just ends up being "goto alternativeExit".
Rusky wrote:
Brendan wrote:This is a continuation of the same problem - the offset of Rect structure within the union is different for the enumeration's Recangle and Both, so you're forced to have an ugly switch/case thing inside "calcRectangleArea()".
So you don't actually want a union then.
That was the entire point of the original example. With unions the programmer has to decide if they want a union or a structure for no reason other than optimising memory layout by hand; and then if/when they make minor changes to the way their data is used (when a union needs to become a structure, or when then want a structure to become a union) they have to change every single place it was used in all of their code. If the compiler did structure member co-location, then programmers don't need to choose and can just use structures for everything, and if/when they make minor changes to the way their structure is used there is no "change every single place it was used in all of their code" hassle.
Rusky wrote:
Brendan wrote:If the compiler can determine that circle, rectangle and square are never used at the same time; then it can co-locate the structure members and the structure can be just as good as a union. If the programmer makes a minor change (e.g. so that rectangle and circle might be used at the same time) then with no additional changes whatsoever everything continues to work perfectly.
That sounds an awful lot like the compiler doing things behind your back, [url=http://forum.osdev.org/viewtopic.php?p=232051#p232051]which I thought you didn't like[url].
The compiler has to do some things. For example, it'd probably be bad if the compiler expected programmers to explicitly specify the address of every piece of global data and every function, or explicitly specify the offset of each structure member within a structure. The compiler has to figure these things out to make programming easier for the programmer. All I'm doing is improving how the compiler figures out these things. It doesn't causes additional/unexpected instructions, or hidden function calls, hidden memory allocations/deallocations, etc in the final executable.
Rusky wrote:For someone who wants a programming language not to introduce too much to beginners, you sure like pointers. Empirically speaking that's one of the hardest things for beginners to learn.
I really don't know why beginners have trouble with pointers (I knew 6502 assembly before I was introduced to pointers, and for me it 2 seconds of "what's this gibberish" followed by "D'oh, pointers are just addresses").

I suspect there's 3 reasons:
  • not having any idea how a computer's hardware works. Every beginner programming course should begin with a simplified description of RAM and instructions ("RAM is like a grid of boxes where each box contains a number...").
  • languages with inconsistencies (examples for C include "foo(myStruct)" vs. "foo(myArray)" where one is passed by value and the other isn't, and "myInteger == *(&myInteger)" vs. "myArray == *(&myArray)" where one is true and the other is insane)
  • operator precedence rules
I can't do anything about the first problem. The other 2 problems I can fix.

Of course if you try to avoid pointers, you just end up replacing the word "pointer" with the word "reference" in your language's documentation.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Unions, program proofs and the Halting Problem

Post by Brendan »

Hi,
embryo wrote:
Brendan wrote:Of course you're right - if a try to get it right and fail; then I can try to hide my failure behind pragmas/annotations later on.
Does it means you are trying to create your personal language first? I suppose it should be something like C. And C was Java's starting base, also. Are you creating better Java? :)
I'm mostly fixing all the problems with C, to create a language that's better than C for low level programming. Note that for low level programming it's impossible to create a language that's better than C without also creating a language that's better than Java.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: The Mill: a new low-power, high-performance CPU design

Post by Rusky »

Brendan wrote:The alternative exit provided by the caller must be a label in the caller; and all the compiler does is insert a "mov [esp],???" instruction to change the function's return address before doing "ret". Of course if the function is inlined into another function then "return alternativeExit" just ends up being "goto alternativeExit".
...which is exactly the way Option would keep error handling out of the critical path, without introducing labels, making it yet another feature the programmer has to learn.
Brendan wrote:With unions the programmer has to decide if they want a union or a structure for no reason other than optimising memory layout by hand;
I use unions (and ADTs) for semantic reasons, not for optimization. It conceptually makes sense to say "this is type A or type B, but not both." I don't really care about the optimization.
Brendan wrote:It doesn't causes additional/unexpected instructions, or hidden function calls, hidden memory allocations/deallocations, etc in the final executable.
But it does cause larger structure sizes and move members around. What if you had more than just one or two cases in the union, and all of a sudden your variable doesn't fit in a register (or a cache line!)? What if you use the union for parsing some system table? Then the compiler is making extra costs or breaking things without making it visible to you.
Brendan wrote:I really don't know why beginners have trouble with pointers (I knew 6502 assembly before I was introduced to pointers, and for me it 2 seconds of "what's this gibberish" followed by "D'oh, pointers are just addresses").
It's because you've been cursed with being unable to "see things from the perspective of a beginner learning their first language." Don't believe me? Go ask a computer science teacher.
Brendan wrote:not having any idea how a computer's hardware works. Every beginner programming course should begin with a simplified description of RAM and instructions ("RAM is like a grid of boxes where each box contains a number...").
It's this one, but even worse, because that explanation doesn't always help (speaking from experience teaching pointers).

My point is not that you should remove pointers, but that you can't use "it's too hard for beginners" on its own as a reason to avoid something.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: The Mill: a new low-power, high-performance CPU design

Post by Brendan »

Hi,
Rusky wrote:
Brendan wrote:The alternative exit provided by the caller must be a label in the caller; and all the compiler does is insert a "mov [esp],???" instruction to change the function's return address before doing "ret". Of course if the function is inlined into another function then "return alternativeExit" just ends up being "goto alternativeExit".
...which is exactly the way Option would keep error handling out of the critical path, without introducing labels, making it yet another feature the programmer has to learn.
Show me how to do this with your Option (while still trying to pretend there's no conditional branch on the critical path):

Code: Select all

retry:
    do_something(retry)
I didn't introduce labels for alternative exists. I stole labels from assembly and C where they were introduced for other reasons (goto and switch/case targets), and then recycled them.

Also note that alternative exits are also supported in assembly language, e.g.:

Code: Select all

speedLimit as const auto = 100

asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
    eax = invoke calcAverageSpeed(eax, ebx, tooFast)
    cmp eax,speedLimit
    ja tooFast
    mov eax,false
    ret

tooFast:
    mov eax,true
}

asmfunction calcAverageSpeed(distance as u32 in eax, seconds as u32 in ebx, error as exit in ebp) (speed as u32 in eax) {
    test eax,eax
    je badArgs
    div
    ret

badArgs:
    exit ebp
}
It also means that you can do this:

Code: Select all

speedLimit as const auto = 100

multitarget checkIfTooFast(distance as u32, seconds as u32) (result as bool) {

    ; Generic function (only used when no suitable assembly found for target machine)

    functiondef checkIfTooFast(distance as u32, seconds as u32) (result as bool) {
        if(calcAverageSpeed(distance, speed, tooFast) < speedLimit) {
            return false;
        } else {
    tooFast:
        return true;
    }

    ; Equivalent for 32-bit 80x86 assembly (only used when compiling for 32-bit 80x86)

    asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
        eax = invoke calcAverageSpeed(eax, ebx, tooFast)
        cmp eax,speedLimit
        ja tooFast
        mov eax,false
        ret
    tooFast:
        mov eax,true
    }

}
Rusky wrote:
Brendan wrote:With unions the programmer has to decide if they want a union or a structure for no reason other than optimising memory layout by hand;
I use unions (and ADTs) for semantic reasons, not for optimization. It conceptually makes sense to say "this is type A or type B, but not both." I don't really care about the optimization.
That's a silly artificial difference. Semantically, a structure is identical to an untagged union (if the union is used correctly).
Rusky wrote:
Brendan wrote:It doesn't causes additional/unexpected instructions, or hidden function calls, hidden memory allocations/deallocations, etc in the final executable.
But it does cause larger structure sizes and move members around. What if you had more than just one or two cases in the union, and all of a sudden your variable doesn't fit in a register (or a cache line!)? What if you use the union for parsing some system table? Then the compiler is making extra costs or breaking things without making it visible to you.
What if you write "a * 4" and the compiler doesn't convert it into a left shift? What if you write "int myArray[1234] = "hello";" and the compiler doesn't realise the array is never accessed? What if you have a massive "unusedBloat()" function and the compiler doesn't discard it?

How is a structure member co-location optimisation any different to any other optimisation that compilers have been doing for the last 50 years, where the actual behaviour of the program doesn't change at all (other than speed and/or memory usage) regardless of whether the optimisation is done or not?
Rusky wrote:
Brendan wrote:I really don't know why beginners have trouble with pointers (I knew 6502 assembly before I was introduced to pointers, and for me it 2 seconds of "what's this gibberish" followed by "D'oh, pointers are just addresses").
It's because you've been cursed with being unable to "see things from the perspective of a beginner learning their first language." Don't believe me? Go ask a computer science teacher.
Perhaps this might help (first hit on Google searching for "why are pointers hard to understand"). Here's the most relevant part:

"Most of my students were able to understand a simplified drawing of a chunk of memory, generally the local variables section of the stack at the current scope. Generally giving explicit fictional addresses to the various locations helped.

I guess in summary, I'm saying that if you want to understand pointers, you have to understand variables, and what they actually are in modern architectures.
"
Rusky wrote:
Brendan wrote:not having any idea how a computer's hardware works. Every beginner programming course should begin with a simplified description of RAM and instructions ("RAM is like a grid of boxes where each box contains a number...").
It's this one, but even worse, because that explanation doesn't always help (speaking from experience teaching pointers).
I think that, in some ways, there is no right way to teach programming (at least not programming as it exists today). Some (most?) teachers think it's a good idea to teach students high level programming first, and then move towards low level after. This leads to difficulty understanding low level concepts (as students end up trying to understand low level things in the context of high level constructs).

Some (less?) teachers think it's better to teach from the ground up, starting with low level and then moving towards high level. This leads to difficulty understanding high level concepts (as students end up trying to understand high level constructs in the context of low level things).

For me personally; I think the high level constructs do more harm than good anyway; and the best way to teach programming is to start with low level and then move towards "medium level", and forget about the high level nonsense completely. :)

More seriously; I see it as an indication that language designers have failed to make programming easier (and have actually made everything far more complex than it ever needed to be).
Brendan wrote:My point is not that you should remove pointers, but that you can't use "it's too hard for beginners" on its own as a reason to avoid something.
My point is that people learn to cope with things, and this changes their perceptions. For example; someone who has become used to polymorphic classes saying that unions make things easier is a little bit like a blind man saying that dyslexia sounds like fun.

To get rid of the "My arm got bitten off by a shark, and you think paper cuts are bad?" problem it's best to look for people who haven't learn to cope with things and haven't had their perceptions changed.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
embryo

Re: Unions, program proofs and the Halting Problem

Post by embryo »

Brendan wrote:I'm mostly fixing all the problems with C, to create a language that's better than C for low level programming.
Is it a new language (with new rules and new compiler) or is it the C with a lot of new pragmas? I know, that using pragmas it is possible to introduce new rules, but there should be compiler support for new rules without pragmas for a language to be called 'new'.

Is the following example possible to compile using standard C compiler with heavy pragma overusing or it is just an example of some imaginary new language?

Code: Select all

asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
    eax = invoke calcAverageSpeed(eax, ebx, tooFast)
    cmp eax,speedLimit
    ja tooFast
    mov eax,false
    ret

tooFast:
    mov eax,true
}
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Unions, program proofs and the Halting Problem

Post by Brendan »

Hi,
embryo wrote:
Brendan wrote:I'm mostly fixing all the problems with C, to create a language that's better than C for low level programming.
Is it a new language (with new rules and new compiler) or is it the C with a lot of new pragmas? I know, that using pragmas it is possible to introduce new rules, but there should be compiler support for new rules without pragmas for a language to be called 'new'.
It's a new language. C influenced the design of my language in the same way that C influenced the design of Java.
embryo wrote:Is the following example possible to compile using standard C compiler with heavy pragma overusing or it is just an example of some imaginary new language?

Code: Select all

asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
    eax = invoke calcAverageSpeed(eax, ebx, tooFast)
    cmp eax,speedLimit
    ja tooFast
    mov eax,false
    ret

tooFast:
    mov eax,true
}
It's an example of inline assembly within my new language.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Rusky
Member
Member
Posts: 792
Joined: Wed Jan 06, 2010 7:07 pm

Re: The Mill: a new low-power, high-performance CPU design

Post by Rusky »

Brendan wrote:Show me how to do this with your Option (while still trying to pretend there's no conditional branch on the critical path)
You just write the conditional branch, because that's the easiest to read and write (remember performance was last on your priority list), and then the compiler does a partial inline so that the branch in the function that decides which value to return also goes directly to the branch in the caller. There, branch eliminated.
Brendan wrote:
Rusky wrote:I use unions (and ADTs) for semantic reasons, not for optimization. It conceptually makes sense to say "this is type A or type B, but not both." I don't really care about the optimization.
That's a silly artificial difference. Semantically, a structure is identical to an untagged union (if the union is used correctly).
No, it's not semantically identical. If you try to use multiple members of a struct at once, you don't get an error. If you try to use multiple members of a (type safe) union at once, you get an error. That's the behavior unions should expose to the programmer. It's telling that Rust extended enums rather than structs to get that behavior. Like I said, I don't care about performance here- I care that the compiler can catch errors (your top priority for a language), rather than silently update the semantics of the program so it's "not an error."
Brendan wrote:Perhaps this might help (first hit on Google searching for "why are pointers hard to understand").
The fact that there is such an article shows that pointers are hard. Not that there isn't a solution, or that we don't need them (there is and we do), but that some parts of programming are fundamentally hard, so you can't just dismiss a programming language feature because it's "hard."

For example, people dismiss static typing because their compiler yells at them when they get the details wrong, even when their program is still correct and they just don't know how to express that to the type system. People advocate garbage collection because it's easier to program with, even though they would write better programs (even in a GC'd language) if they understood memory management.

I also don't understand your aversion to polymorphism, nor what polymorphism has to do with unions...?
embryo

Re: Unions, program proofs and the Halting Problem

Post by embryo »

Brendan wrote:

Code: Select all

asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
    eax = invoke calcAverageSpeed(eax, ebx, tooFast)
    cmp eax,speedLimit
    ja tooFast
    mov eax,false
    ret

tooFast:
    mov eax,true
}
It's an example of inline assembly within my new language.
Your language is interesting :)
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: Unions, program proofs and the Halting Problem

Post by Antti »

Brendan wrote:

Code: Select all

asmfunction x86_32 checkIfTooFast(distance as u32 in eax, seconds as u32 in ebx) (result as bool in eax) {
    eax = invoke calcAverageSpeed(eax, ebx, tooFast)
    cmp eax,speedLimit
    ja tooFast
    mov eax,false
    ret

tooFast:
    mov eax,true
}
There was one thing that caught my attention. I am not thinking this is a serious reference example of your programming language but now that it came up, I would like to ask questions. I thought you wanted to give some freedom to the prologue and epilogue implementations if you use "asmfunctions" rather than "asmroutines". In this case there is no reason to have any so the "ret" would logically make sense. However, specifications must be strict and nothing would prevent a naive compiler impementation reserving space for unnecessary local variables (unless a different specification prevents this).

Am I wrong if I think the "ret" should definitely be a "exit"? Would that be according to your draft specification? This is a discussion you end up being right because it is your programming language and your specification but at least I think the "exit" would be better in any case. A good extra abstraction that does not harm but brings advantages. Other question: how many reserved words you end up having in your programming language?

Note! This was a very pedantic note but I like when everything is just "correct" and not "fuzzy" and this was a chance to ask details about the new language.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: The Mill: a new low-power, high-performance CPU design

Post by Brendan »

Hi,
Rusky wrote:
Brendan wrote:Show me how to do this with your Option (while still trying to pretend there's no conditional branch on the critical path)
You just write the conditional branch, because that's the easiest to read and write (remember performance was last on your priority list), and then the compiler does a partial inline so that the branch in the function that decides which value to return also goes directly to the branch in the caller. There, branch eliminated.
So in general, Rust's Options don't avoid branches in the caller but sometimes branches can be optimised out, while for my alternative exits the caller didn't have a branch to optimise out.
Rusky wrote:
Brendan wrote:
Rusky wrote:I use unions (and ADTs) for semantic reasons, not for optimization. It conceptually makes sense to say "this is type A or type B, but not both." I don't really care about the optimization.
That's a silly artificial difference. Semantically, a structure is identical to an untagged union (if the union is used correctly).
No, it's not semantically identical. If you try to use multiple members of a struct at once, you don't get an error. If you try to use multiple members of a (type safe) union at once, you get an error. That's the behavior unions should expose to the programmer. It's telling that Rust extended enums rather than structs to get that behavior. Like I said, I don't care about performance here- I care that the compiler can catch errors (your top priority for a language), rather than silently update the semantics of the program so it's "not an error."
For the purpose of creating pointless hassles for programmers; let's create a stupid artificial rule like "all numerical constants must be preceded by the letter 'e' if even and preceded by the letter 'o' if odd"; and then pretend that even and odd are semantically different. That way, if a programmer does "e123" we can catch that error!

For the purpose of creating pointless hassles for programmers; let's create a stupid artificial rule like "if you only use one member of a structure at a time, then use a union"; and then pretend that structures and unions are semantically different. That way, if a programmer does use one structure member at a time we can catch that error!

I do care that the compiler can catch errors, but only using one member of a structure at a time is not an error - it's only pointless hassle for programmers.

Note: there are cases where differences in memory layout are externally visible (e.g. data used for messages, networking and file IO; and devices with memory mapped registers). Neither a structure nor a union is suitable for any of these cases. For these cases I have "rigid structures" where the compiler makes guarantees about the order of structure members, size of structure members, padding, and endian-ness (and also imposes a few restrictions - e.g. members can't be pointers).
Rusky wrote:
Brendan wrote:Perhaps this might help (first hit on Google searching for "why are pointers hard to understand").
The fact that there is such an article shows that pointers are hard. Not that there isn't a solution, or that we don't need them (there is and we do), but that some parts of programming are fundamentally hard, so you can't just dismiss a programming language feature because it's "hard."

For example, people dismiss static typing because their compiler yells at them when they get the details wrong, even when their program is still correct and they just don't know how to express that to the type system. People advocate garbage collection because it's easier to program with, even though they would write better programs (even in a GC'd language) if they understood memory management.
I'm not dismissing pointers - for that case the flexibility/power of pointers outweigh the "harder to learn" disadvantage; and I can't think of any alternative that isn't worse (for low level programming).

I am dismissing unions - for that case there are no advantages to outweigh the "harder to learn" disadvantage. It's just pure hassle for no sane reason (other than making a compiler's optimiser easier to write).
Rusky wrote:I also don't understand your aversion to polymorphism, nor what polymorphism has to do with unions...?
Here's a union in C:

Code: Select all

typedef union {
	int foo;
	char *bar;
} MY_UNION;
Here's the same thing in Java (which doesn't support unions):

Code: Select all

class MY_UNION {
}

class Foo extends MY_UNION {
    int foo;
}

class Bar extends MY_UNION {
    char *bar;
}

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Unions, program proofs and the Halting Problem

Post by Brendan »

Hi,
Antti wrote:Am I wrong if I think the "ret" should definitely be a "exit"?
You're right - it should have been "exit" and not "ret'. :oops:


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Unions, program proofs and the Halting Problem

Post by thepowersgang »

(this will possibly get me slightly flamed)

I prefer the idea of having tagged unions avaliable. Sure they're complex to learn, but the huge benefit is you can annotate that these two fields should NEVER be used at the same time, and the compiler will either compile-time check that each access is valid, or when it can't, emit an assertion to prevent undefined behavior (I guess it's kinda like C++ inheritance and dynamic casting, but with a simpler represenation)

With tagged unions, you communicate to the compiler your intention, and it makes sure that you don't accedentally go against that intention.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Post Reply