Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

C is crap

Name: Anonymous 2015-09-08 21:42

The next time I hear some idiot say ``an array is just a pointer'' I'm going to write an OS in Haskell and remotely install it on their computer.

Name: Anonymous 2015-09-14 20:42

Any advice on selling a rewrite and/or challenges as one nears 1B daily queries for which Haskell would be uniquely advantageous?

Haskell's just really good at anything enterprise really. Frontend JS, API, traditional web backend. As long as you avoid weird/unpleasant libraries and you're proficient/comfortable in Haskell it can be a great experience. Libraries in Haskell are generally pretty opinionated so you need to make sure you know what you like. HLearn is a good example of that opinionatedness being very fecund but also unusual to people accustomed to more ordinary ML libraries. HLearn is super cool :)

Name: Anonymous 2015-09-14 20:43

>>30
So continuations are just theoretical semantics for GOTO.

Name: Anonymous 2015-09-14 21:03

>>34,36,38
The Algol and PL/I goto and Lisp's tagbody/go unwind the stack to the correct point.
These were universally considered to be gotos several years before C or setjmp/longjmp existed.
Landin's paper was about interpreting the goto in Algol 60 in lambda calculus, including non-local gotos, using continuations.

"setjmp/longjmp" had to be invented because C doesn't have nested procedures.
We get to that same thing about limitations in C confusing people again, but this time it's goto.

Name: Anonymous 2015-09-14 21:15

>>41

--Insert Any Language Here--'s just really good at anything enterprise really.

Name: GNG is Not GNU 2015-09-14 21:21

>>43

In some cases nested procedures seem useful, and are almost like closures.. but they can also encourage hierarchies like OOP trees of this junk inside this junk, inside this, inside this, and your code wiggles off the screen with a bunch of nests. Whereas C code goes down the screen one procedure at a time without any trees of procedures nested in trees of procedures. So I'm not convinced either way that nests of procedures are a good thing, although sometimes they are. Richard Stallman is a fan of nested procedures and allowed C to have them in GCC, if you turn that feature on with a compiler option, I think. I don't know if many people use this feature. Also, Lisp suffers a similar problem of functionsinsidefunctionsinside(functions(insidefunctions))

Name: Jesus Freak 2015-09-14 21:42

Name: Anonymous 2015-09-15 16:54

>>42
that's exactly what they're NOT

>>43
good post

Name: Engine Stalled 2015-09-16 0:03

>>47
"Landin's paper was about interpreting the goto in Algol 60 in lambda calculus"

becomes "Landin was an academic trying to justify goto by pretending it was somehow justified inside lambda calculus by moving the goal posts and pretending that somehow gotos could become the emperor in new clothes by renaming them to continuations. All this beating around the bush really meant, that functional programmer were envious of imperative languages so they needed to implement imperative programming into functional programming while pretending that it was still functional."

Wikipedia: "Continuations are the functional expression of the GOTO statement"

that's exactly what they ARE. Bad post.

Name: Anonymous 2015-09-16 9:22

>>48
If that is what it says then wikipedia is wrong in this case. I'm sooooooooooooooo sorry but even wikipedia can be wrong on occasions.

Name: Anonymous 2015-09-16 15:35

Anyone citing wikishit as a credible source is trolling.

Name: Anonymous 2015-09-16 18:29

There are theoretical GOTO is changing the instruction pointer. One generalization is the procedure call which is a GOTO (set the instruction pointer to the function body) that also passes parameters. Half of the time at least one parameter is a continuation. The continuation is implicitly passed at a procedure call unless you code in CPS.

A continuation is a closure - a pointer to instructions and an environment. When procedure foo calls procedure bar, it creates a closure of the local variables and the address of the next instruction, and passes this continuation together with other arguments to bar. When bar is done it calls the continuation with the value(s) it computed, which means that the variable environment of the continuation is entered and the instruction pointer is changed.

A common optimization is to use a stack to allocate the continuation closures. The local variables, the return address and the arguments are pushed when calling a procedure, and the stack and instruction pointers are restored when you return. This works because in most programming languages a callee has a shorter activation duration than a caller, so closure allocation occurs in FIFO order. This also makes some people confuse a continuation and a call stack. A tail-call when a caller doesn't create a closure and instead passes the one it received when it was called.

Name: Anonymous 2015-09-16 18:55

Another take on continuations come from the actor model. We can consider a function call to be the creation of an actor, where the parameters form a message and the function body its script. Then the act of returning from a procedure is passing a message back to the parent actor. Each actor has one parent (the one that created the actor) and can create zero or more child actors. An actor receives one message from its parent and sends one message back.

Each actor has its own instruction pointer that advances independently from others. Potentially actors could act in parallel, but in practice a parent almost always waits for a child to respond before continuing. This means that only one actor runs at a time, and every other actor waits for its child to respond.

Also in this case is it possible to allocate actors on a stack. When an actor is created we save the instruction pointer of the current actor on the stack along with the message we send to the child and begin executing the script of the child. When we send a message back to the parent we save the return values in a designated location and restore the parent's instruction pointer.

A continuation in the actor model is an actor waiting for a child to respond. If an actor A passes a reference to its parent as part of the message when it creates a child actor, then the child actor can send a message to the actor A's parent directly, bypassing A entirely.

We can also interpret first class continuations in this context. It is an actor that waits for a message from any actor that happens to know of it.

Name: Anonymous 2015-09-16 19:58

"At its heart, call/cc is something like the goto instruction (or rather, like a label for a goto instruction); but a Grand High Exalted goto instruction... The point about call/cc is that it is not a static (lexical) goto instruction but a dynamic one (David Madore's A page about call/cc)" --HaskellWiki

But I guess anything from a "wiki" is considered trash by the progrider "experts". Since haskell uses a wiki for a lot of their documentation, that must mean haskell is trash (sarcasm)

Name: Anonymous 2015-09-16 20:53

>>53
You're confusing Wikipedia with MediaWiki, which is like saying because one book is garbage then anything from a printing press must be. Fucking moron.

Name: Anonymous 2015-09-16 21:01

dubs

Name: Anonymous 2015-09-16 21:29

>>53
The point about call/cc is that it is not a static (lexical) goto instruction but a dynamic one
Those are usually called exceptions (but not the only kind of exception).

Name: Anonymous 2015-09-17 8:17

>>53
letting hasktards explain anything
heh

Name: Anonymous 2015-09-17 18:45

>>57
Whom are you quoting?

Name: Anonymous 2015-09-19 7:12

Are there any other contexts where an array identifier doesn't decay into a pointer of its first element than sizeof arr and &arr?

Name: Anonymous 2015-09-19 9:51

>>59
No.

Name: Dennis McLeod Richie 2015-09-20 14:30

I think much of the confusion wrt arrays and pointers that novice C programmers have is that books and lectures tend to conflate the concepts of identifiers, objects and types. Every object has an address, whether they have automatic, static or dynamic extent. An identifier for a variable is a symbol that refers to an object. Text, like natural language, is serial so we give names to things so that we can easily refer to them. But the identifier is not the object.

Using the address of operator we get a pointer value that refers to the object. Now we can use either the identifier or the pointer to access the object, but neither of them are the object.

An array is a type, which signifies that the object is large enough to hold N elements of type T. We can use the name (identifier) of the array with to refer to the object, but there is very little we can do with an array (sizeof/alignof, and address of). Instead we operate on it through pointers, and the compiler makes this convenient to do. But the array type is not the object, the pointer to the first element is not the object and the identifier is still not the object.

But maybe this is too hard to learn during your first exposure.

Name: Anonymous 2016-08-26 5:39

>>1
An identifier referring to an array, under some circumstances, is treated as a pointer to the first element of an array. Likewise, ANY pointer can be dereferenced using array notation, ptr[5] means to read data at an offset of 5 * (sizeof whatever data type the pointer is using) from the pointer itself.

However, it's important to know that arrays are allocated on the stack like ordinary non-global, non-static variables, not on the heap like the blocks returned by a call to the standard memory allocation function malloc(). Because of this, you cannot declare an array within a function, and then return it to the caller via pointers - when the function returns, the array will go out of scope and be destroyed, leaving you with a pointer to nothing (i.e. undefined behavior). Arrays instead can be thought of as using the alloca() allocator, which allocate data on the parent function's stack.

So
int * getarray(void) {
int a[5];
return a;
}

and
int * getarray(void) {
int * a = alloca(5 * sizeof (int));
return a;
}

basically do the same thing (though the first will issue a compiler warning, due to the implicit conversion of an array to a pointer, which is clearly suspicious if it happens while returning a local variable). And neither will do the obviously intended behavior of usefully returning a pointer to an array. What would do that is
int * getarray(void) {
int a * = malloc(5 * sizeof (int));
return a;
}

This works because malloc() allocates memory on the heap, not the stack, and so it persists even when the function goes out of scope.

>>7
Not having a boolean type != not knowing what a Boolean is. Having an explicit boolean type in a language where the smallest unit of storage is the byte is silly anyway, unless it's implemented as bitfields and packed so _Bool bools[8] takes up one byte. As long as you have a sane way of handling numerical values as input to the if statement or similar, there's no need for explicit booleans.

>>8
Everything is goto, jump/branch is the only control flow statement found in most instruction sets, and it's basically a goto. Even C, which tries to divorce itself from the goto statement, uses it directly in its switch statement. And if "for", "while", "do", "switch", and "case" were removed from the language, you could duplicate their functionality with gotos.

Even function calls are gotos, paired with a stack to hold local variables and a return address. The old GOSUB statement in BASIC was basically a primitive version of that: store the current line number in a special variable, GOTO the beginning of a subroutine, and when you hit RETURN go back and pick up where you left off. Later on a single variable to hold return addresses was replaced with a stack to allow nested subroutine calls, then finally the stack allowed functions to hold their own local variables in the stack as well. Ultimately, it's still all GOTOS though.

Name: Anonymous 2016-08-26 6:22

Does LISP have an equivalent to 'computed goto'?
https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

Name: Anonymous 2016-08-26 7:14

>>63
in implementations that use a CPS transform, all function calls are equivalent to goto, so all functions are equivalent to "labels as values".

in implementations that implement proper tail calls but not a CPS transform, all function calls in tail position are equivalent to goto.

Name: Anonymous 2016-08-26 11:32

>>64
all function calls are equivalent to goto
this is completely false, why do you keep saying this?

Name: Anonymous 2016-08-26 11:32

>>64
function calls in tail position are equivalent to goto
no they are not

Name: Anonymous 2016-08-26 11:59

every instruction that affects control flow is equivalent to goto. to solve this problem, we should compile everything with the only acceptable compiler: movcc

Name: Anonymous 2016-08-26 16:15

>>63
Not that I'm aware. That's a bitch of a feature to add to a language whose GC can move code blocks around in the middle of execution. I presume that's also a GCC-specific feature? Leave it in statically compiled languages.

Name: Anonymous 2016-08-26 17:31

Name: Anonymous 2016-08-26 18:43

>>65
Function calls are a specific mechanism implemented with goto. In addition to executing GOTO to the start of the function code, it also pushes the current instruction address onto the stack, and also reserves sufficient space in the stack frame for all the function's local variables. When the function returns, the local variables are deallocated and the return address is popped off the stack and assigned to the instruction pointer, so execution can pick up where it left of.

>>66
They are, with tail-call optimization. Tail recursion provides functionality equivalent to a loop, while if unoptimized will use up unnecessary stack space. TCO transforms it into a loop, which is implemented in machine code with a jump or branch instruction, which is the same as a GOTO.

>>68
I presume that's also a GCC-specific feature?
It's a GNU extension, so not part of any C standard. TCC supports it as well, but most C compilers do not. And the standard switch statement can be considered a form of computed goto.

Name: Anonymous 2016-08-26 21:01

>>66
why did you cut off the first part of that sentence?

in cps, function calls are implemented with a goto

Name: Anonymous 2016-08-26 21:02

>>70
TCO transforms it into a loop, which is implemented in machine code with a jump or branch instruction, which is the same as a GOTO.

No. TCO doesn't transform anything into a loop, it transforms a call into a jump. If it's a jump to the current function, that effects a loop. If it's a jump to any other function, it's not a loop.

If you can only transform calls to the current function, your language is SHIT.

Name: Anonymous 2016-08-26 21:03

>>68
In languages with proper tail calls, a function value is equivalent to "labels as values".
Dumb shitposter

Name: Anonymous 2016-08-26 21:24

>>70
no they are not.

>>71
"function calls are implemented with a goto" is true, but they are not gotos.

Name: Anonymous 2016-08-26 21:26

"tail calls are gotos" is the kind of idiotism i expect on reddit and hacker news, not /prog/. nu/prog/ is much stupider than old/prog/, back when we were on 4chan. It's disappointing.

Name: Anonymous 2016-08-26 21:44

All branching constructs are just gotos with additional features added.

Name: Anonymous 2016-08-26 22:58

(stopping the dubsquatter from dubsquatting)

Name: Anonymous 2016-08-26 23:15

dubs+1

Name: Anonymous 2016-08-27 4:51

>>72
Tail recursion is different from tail call optimization, in that the stack frame can be handled differently between the two. Tail recursion can work with the new parameter values in-place.

Name: Anonymous 2016-08-27 7:20

>>79
Tail recursion can work with the new parameter values in-place.
which is a poor implementation

proper tail calls should be implemented by garbage collecting unecessary stack frames ala chicken

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List