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

Pages: 1-4041-8081-120121-

PROGRAMMING CHALLENGE

Name: Anonymous 2010-07-16 18:57


This one should be difficult enough for you guys,

Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i.


My submission, in Scheme


(define (foo num)
  (lambda (x) (+ x num)))

Name: Anonymous 2010-07-16 19:00


(defun foo (n)
  (lambda (i)
    (+ n i)))

Name: Anonymous 2010-07-16 19:02

anyone got a solution for this in C?

Name: 2 2010-07-16 19:10

>>3
Ignoring the "static" solution (not a real one), you could write this in 2 main ways:
1) Unportable: malloc a buffer, and write the function code to it, insert n's value in the function code. Not hard to do, but not portable.
2) Portable: make a FUNCALL-like macro, which calls a function with a context struct or value cell array, and have the function use the values in the struct (in this case, the value of n).

In the case 2, a function is either a piece of code or a structure which contains the address of a real function and an array or structure of values closed over (or pointers to them). A funcall function or macro can call the real function or the encapsulated structure (containing the real function and closed over values). This is how most Lisps do it, but it's done behind the scenes, so you don't really need to know how closures are implemented.

Name: Anonymous 2010-07-16 19:23

Here's my solution in C++0x:


std::function<int(int)> foo(int n) {
   return [](int i) { return i + n; }
}

Name: Anonymous 2010-07-16 19:25

>>3
int (*foo(int n))(int)
{ int f(int i)
  { return n + i; }
  return f; }

Name: Anonymous 2010-07-16 19:28

And here's the old C++ way to do it using templates and compile-time functors, although it's not exactly the same thing as actual lambdas and closures that are in C++0x.


template< int N >
struct foo
{
    int operator()(int i) {
        return i + N;
    }
};

Name: Anonymous 2010-07-16 19:31

>>def foo(n): return (lambda i: i+n)
>>foo(5)(1)
>>6

PyWut?

Name: Anonymous 2010-07-16 19:35

>>6
This only works in C99, not in C89 or C++.

Name: Anonymous 2010-07-16 19:40

>>9
How does the C99 compiler implement it? Or it is undefined, and it's up to the compiler to decide which approach to take?

Name: Anonymous 2010-07-16 19:47

>>10
test.c:

#include <stdio.h>

int (*foo(int n))(int) {
    int f(int i) { return n + i; }
    return f;
}

int main(int argc, char* argv[]) {
    int (*fun)(int) = foo(10);
    printf("%d\n", fun(2));
    return 0;
}


With GCC 4.5 gcc -std=c99 -O2 -S -c test.c, the assembly listing on x86-64 looks like this:


    .file    "test.c"
    .text
    .p2align 4,,15
    .type    f.1848, @function
f.1848:
.LFB4:
    .cfi_startproc
    movl    (%r10), %eax
    addl    %edi, %eax
    ret
    .cfi_endproc
.LFE4:
    .size    f.1848, .-f.1848
    .p2align 4,,15
.globl foo
    .type    foo, @function
foo:
.LFB3:
    .cfi_startproc
    leaq    -36(%rsp), %rax
    ret
    .cfi_endproc
.LFE3:
    .size    foo, .-foo
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string    "%d\n"
    .text
    .p2align 4,,15
.globl main
    .type    main, @function
main:
.LFB5:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $10, %edi
    call    foo
    movl    $2, %edi
    call    *%rax
    movl    $.LC0, %edi
    movl    %eax, %esi
    xorl    %eax, %eax
    call    printf
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE5:
    .size    main, .-main
    .ident    "GCC: (GNU) 4.5.0"
    .section    .note.GNU-stack,"x",@progbits

Name: Anonymous 2010-07-16 19:48

EXPERT C SOLUTIONS!
Works for 0 >= n >= 7 . Could be extended for a larger range of n


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int (**F)(int);

int F00(int i) { return 0 + i; }
int F01(int i) { return 1 + i; }
int F02(int i) { return 2 + i; }
int F03(int i) { return 3 + i; }
int F04(int i) { return 4 + i; }
int F05(int i) { return 5 + i; }
int F06(int i) { return 6 + i; }
int F07(int i) { return 7 + i; }

int main(int argc, char **argv) {
    unsigned long n,i;
    printf("n:%lu\n",n);
    F = malloc(8*sizeof(void*));
    F[0] = F00;
    F[1] = F01;
    F[2] = F02;
    F[3] = F03;
    F[4] = F04;
    F[5] = F05;
    F[6] = F06;
    F[7] = F07;
    n = argv[1] ? strtoul(argv[1],0,10) : 0;
    i = argv[2] ? strtoul(argv[2],0,10) : 0;
    int (*f)(int) = F[n];
    printf("answer:%d\n",f(i));
    return 0;
}

Name: Anonymous 2010-07-16 19:56

>>12
Wrong. A real EXPERT C89 PROGRAMMER would use the preprocessor.


#define FOO(n) F##n
#define MAKE_FOO(n) int F##n##(int i) { return n + i; }

MAKE_FOO(0)
MAKE_FOO(1)
MAKE_FOO(2)
MAKE_FOO(3)
MAKE_FOO(4)
MAKE_FOO(5)
MAKE_FOO(6)
MAKE_FOO(7)

int main(int argc, char **argv) {
    int (*f)(int) = FOO(2)
    printf("%d\n", f(11));
    return 0;
}

Name: Anonymous 2010-07-16 20:00

>>13
yhbcppt

Name: Anonymous 2010-07-16 20:02

foo = (+)

:/

Name: Anonymous 2010-07-16 20:06

>>11
It looks like it just creates a closure on the stack to capture the value of 'n' that gets passed in when calling the the returned pointer to 'f' (the compiler already knows it's on the stack after the call to foo, so it optimizes it out).

So it looks to be pretty efficient. Not sure yet what would happen across optimization boundaries.

Name: Anonymous 2010-07-16 20:11

DISCLAIMER: THIS IS A TOY! I DO NOT ACTUALLY CODE LIKE THIS

Should run under ikarus with the iksqlite lib


(import (rnrs) (zeptodyne iksqlite))
(define make-counter
  (letrec* ((db (sqlite-open "/tmp/test.db"))
            (n 0)
            (make-name
             (lambda ()
               (set! n (+ n 1))
               (string-append "counter"
                              (number->string n)))))
           (sqlite-exec db "create table retarded_counter (k string, v integer)")
           (lambda (x)
             (let ((name (make-name)))
               (sqlite-exec db (format "insert into retarded_counter values (~s,~s)" name x))
               (lambda ()
                 (let ((ans (string->number
                             (vector-ref
                              (car (sqlite-exec db (format "select v from retarded_counter where k = ~s" name))) 0))))
                   (sqlite-exec db (format "update retarded_counter set v = ~s where k = ~s"
                                           (+ ans 1) name))
                   ans))))))

Name: Anonymous 2010-07-16 20:15

>>17
If this were real code, it would be a candidate submission for thedailywtf.com.

Name: Anonymous 2010-07-16 20:19

>>18
I have similar pieces of code for doing fibs and facts in the toy/ directory of a library I haven't released yet. Vapourware Quality

Name: Anonymous 2010-07-16 20:21

>>19
By toy/, I hope you mean it's just sample code for testing out the underlying library.

Name: Anonymous 2010-07-16 20:23

method(n, block(i, i + n))

Name: Anonymous 2010-07-16 20:28

>>20
Yes and No. I already have real sample code, this is just for fun. I probably won't include it when/if I do release the cod

Name: Anonymous 2010-07-16 20:32

>>20
No, it's because it's a toy language.
nowumad

Name: >>2 2010-07-16 20:37

(defun foo (n) (curry #'+ n))
Should also work, where you should write or import your currying function (a simple 3-4 line version is easy to write, if you don't have it in a library).

Name: Anonymous 2010-07-16 21:26


Func<int, int> foo(int n) {
    return i => n + i
}

Name: Anonymous 2010-07-16 21:39

>>25
What language is that? C#?

Name: Anonymous 2010-07-16 21:45

>>25
This actually looks sexy, minus the confusion due to the return type being grouped with the argument types.

Name: Anonymous 2010-07-16 21:52

>>6
i know this actually works with gcc, but is it supposed to work? does it work with other c compilers?

Name: Anonymous 2010-07-16 21:56

>>28
It works in any C99 compiler, and it only works in gcc if you specifiy -std=c99 or -std=gnu99.

Name: Anonymous 2010-07-16 22:42

>>29
I highly doubt that, considering that nested functions sadly don't feature in any C standard.

Name: Anonymous 2010-07-16 22:58

>>30
Please explain. I can't be trolled(??) properly with insufficient information.

Name: Anonymous 2010-07-16 23:24

>>31
Try comeau online in c99 mode http://www.comeaucomputing.com/tryitout/

I hope you know that if comeau says that something is wrong, then something is wrong?

Name: Anonymous 2010-07-16 23:30


typedef int(*functionPointer)(int);

int n = 20;

int foo2(int i)
{
    return i += n;
}

functionPointer foo(int n)
{
    functionPointer FPtr = foo2;
    FPtr(n);
    return FPtr;
}

int main()
{
    foo(n);
    return 0;
}

Yeah, I cheated with a global variable.
My first post here by the way.

Name: Anonymous 2010-07-16 23:47

>>32
what about real compilers like the intel one or the sun one?

Name: Anonymous 2010-07-16 23:51

>>34
Intel uses the EDG front-end, the same one that Comeau uses, so it's doubtful.

Not sure about Sun.

There's also Clang which is becoming more and more important, not sure about that either.

Name: Anonymous 2010-07-16 23:58

>>35
Clang appears not to support it: http://clang.llvm.org/docs/LanguageExtensions.html

Name: Anonymous 2010-07-17 0:08

>>35
>>36
>clang does not support nested functions; this is a complex feature which is infrequently used, so it is unlikely to be implemented anytime soon.

Name: Anonymous 2010-07-17 0:09

>>37
That's some self-fulfilling prophecy they got going there. Impressive.

Name: Anonymous 2010-07-17 0:14

Nested functions are complex? It should be one addition to the grammar, taking a total of fifteen seconds. What am I missing?

Name: Anonymous 2010-07-17 0:16

>>39
you're forgetting about closures

Name: Anonymous 2010-07-17 0:23

>>40
No. Supporting nested functions does not necessitate supporting closures.

Name: Anonymous 2010-07-17 0:24

>>41
The GCC nested functions extension support closures, which is what we're talking about.

Name: Anonymous 2010-07-17 0:27

>>42
Well, arguably clang could support closures without supporting nested functions but I don't know how much use that would be.

Name: Anonymous 2010-07-17 0:30

>>43
Oddly enough, Clang supports both Objective-C style blocks (lambda functions and closures) and C++0x lambda functions with closures, but both are implemented through different mechanisms, and both aren't language extensions.

Name: Anonymous 2010-07-17 0:43

>Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i.
a=parseInt(prompt("Enter a number",0));;
eval("function newf(i){return a+i}")
newf(10);

Name: Anonymous 2010-07-17 1:23

>>45
function foo(n){return function(i){return n+i}}
foo(pareInt(prompt('Enter a number', 0)))(10);

Name: Anonymous 2010-07-17 1:35

>>46
You can't reuse that function without declaring it with a name outside function scope. Observe:
function check(){
a=parseInt(prompt("Enter a number",0));;
eval("function newf(i){return a+i}")}
check()
newf(10);//Error: newf is not defined

Name: Anonymous 2010-07-17 1:48


function gen(n)
   return function (i)
      return n + i
   end
end

Name: Anonymous 2010-07-17 1:59

>>48
Only Lua comes close to Lisp in terms of beauty.

Name: Anonymous 2010-07-17 2:33

>>29
It's not C99, it's a GNU extension. You need to give GCC -std=c99 -pedantic to make it complain about non-C99 code.

Name: Anonymous 2010-07-17 2:34

i hate niggers

Name: Anonymous 2010-07-17 2:38

Java can do something like this with nested classes but the effort is not really worth it in most cases.

public class MyThing
{
   abstract class OtherThing
   {
      abstract int add(int x);
   }
   protected int i;

   public MyThing(int a) { i = a; }

   public int add(final int n)
   {
      OtherThing thing = new OtherThing() {
         public int add(int x)
         {
            return n + x;
         }
      };
      return thing.add(i);
   }

   public static void main(String[] args) { }
}


What the hell did I just write?

Name: Anonymous 2010-07-17 2:45

>>52
Why would you do that?
OOP and closures are somewhat equivalent.

A class with a (possibly private) member called i, a constructor which takes i, and an add method which takes n is enough.

Usage would be like:

Adder adder = new Adder(i);
int newValue = adder.Add(n,i);


It's not exactly what OP requested for, but the concepts are somewhat equivalent. It's easier to implement OO systems if you already have closures and macros, but it's harder to implement closures if you only have classes, but aside from that the functionality they present is somewhat equivalent.

Name: Anonymous 2010-07-17 3:03

>>53
I was trying to go for a "nested functions" feel and this was the only way I could think of achieving that.

I suppose I could the Java Method class in some way too but that would be a ridiculous amount of work compared to the simplicity of the request.

Name: Anonymous 2010-07-17 4:08

Any solution which manipulates function pointers is very messy.
(return *func_pointer)(execute_from) vs setting global variable x=n; and using standard function calls

#include <stdio.h>
#include <stdlib.h>
int n=0;
int getn(i){return n+i;}
int main(int agrc,char**argv){
n=10;printf("%i",getn(6));
return 0;
}

Name: Anonymous 2010-07-17 4:18

>>51
Good for you.

Name: Anonymous 2010-07-17 5:03

>>55
Any solution involving globals isn't a real solution as you can't just "make as many functions/closures" as you'd like. You can only "generate" one such function. "Making" another invalidates the previous one.

Name: Anonymous 2010-07-17 5:05

JESUS FUCK PEOPLE WHAT THE FUCK IS WRONG WITH THIS THREAD

Use the motherfucking
  __                      _          __
 | _|   ___    ___     __| |   ___  |_ |
 | |   / __|  / _ \   / _` |  / _ \  | |
 | |  | (__  | (_) | | (_| | |  __/  | |
 | |   \___|  \___/   \__,_|  \___|  | |
 |__|                               |__|
tags in the future.


Sheesh.

Name: Anonymous 2010-07-17 5:28

GolfScript:
~{+}+
Example:
$ echo 6 | ruby golfscript.rb funct.gs
{6 +}

Name: Anonymous 2010-07-17 7:16

>>58
when i'll post Python code i'll take this into account.

Name: Anonymous 2010-07-17 7:23

>>58
Number of Posts with code tags:   18
Number of posts without code tags: 5
78% isn't bad for /prog/

Name: Anonymous 2010-07-17 7:31

>>61
That's like saying that losing a finger is not bad since you still have nine left.

Name: Anonymous 2010-07-17 7:48

>>62
Not really

Name: Anonymous 2010-07-17 7:53

>>61
78% isn't bad for summer /prog/, but I don't think that's really a good enough standard to strive for.

Name: Anonymous 2010-07-17 9:44

>>63
Oh fine.
That's like saying that losing two and one-fifth of a finger is not bad since you still have seven and four-fifths left.

Name: Anonymous 2010-07-17 9:45


foo :: (Num a) => a -> (a -> a)
foo n = \x + n

Name: Anonymous 2010-07-17 9:46

>>65
Percentage pedantry aside, the whole analogy was flawed to begin with.

Name: Anonymous 2010-07-17 9:47

>>66
parse error

Name: Anonymous 2010-07-17 9:50

>>68
right, should be

foo :: (Num a) => a -> (a -> a)
foo n = \x -> x + n

started with haskell just a few days ago

Name: Anonymous 2010-07-17 9:50

>>66
See >>15.

Name: Anonymous 2010-07-17 9:51

>>70
ah. makes sense. ttly forgot about currying

Name: Anonymous 2010-07-17 12:36

>>71
* ttly forgot about vowels

Name: Anonymous 2010-07-17 13:45

>>72
* ttlly forgot the other l

Name: Anonymous 2010-07-17 13:50

Bah, I can't come up with a cool and portable solution for C.

Name: Anonymous 2010-07-17 14:01

function foo(n) {
    return function(i) {
        return n + i;
    }
}

Name: Anonymous 2010-07-17 14:02

ffffffffffffffffforgot a semicolon.

Name: Anonymous 2010-07-18 2:22

>>4
1) would work, except it's more complicated than you make it seem; for instance malloc'd memory is execution-protected on modern operating systems. Honestly to make it portable, your best bet is probably to compile it with llvm. You still have to manage the memory containing the closure though, so it's still not like a closure in a typical HLL.

2) does not work because your funcall macro can't be passed around as a function pointer. there's no real way to do it other than return a struct (the closing environment) and pass in that struct in the function call.

In other words it's certainly not possible in standard C, but possible with runtime code generation or compiler extensions.

Name: Anonymous 2010-07-18 4:18

>>6
>>11
int main()
{
    int (*my)(int) = foo(1);
    int (*mi)(int) = foo(2);
   
    printf(" my: %d \n mi: %d\n", my(0), mi(0));

    return 0;
}

my: 2
 mi: 2

EXPERT WINDOWS PROGRAMMERS

Name: Anonymous 2010-07-18 4:21

>>76
You wouldn't need any semicolons for that in Perl but you'd use them anyway.

For some reason I find keeping it on a single line helps me remember the semicolon after curlies. It's also the only excuse I sympathize with for instancing typedefs with their definitions.

Name: Anonymous 2010-07-18 5:32

perl:
sub foo{eval"sub{@_+pop}"}

javascript (1.8+):
foo = function(n) function(i) n + i;

Name: Anonymous 2010-07-18 5:39

>>78
read >>1 again. there is no requirement that precludes returning the same function every time.

Name: Anonymous 2010-07-18 5:44

: foo ( n -- quot ) '[ _ + ] ;

Name: Anonymous 2010-07-18 5:50

>>77
You still have to manage the memory containing the closure though
That's easy, just jmp somewhere else and free the memory, then ret.

Name: Anonymous 2010-07-18 5:52

>>81
I would think best practices would have it covered. If you don't think so too you're fired.

Name: 2,4 2010-07-18 19:09

1) would work, except it's more complicated than you make it seem; for instance malloc'd memory is execution-protected on modern operating systems. Honestly to make it portable, your best bet is probably to compile it with llvm. You still have to manage the memory containing the closure though, so it's still not like a closure in a typical HLL.
If malloc isn't enough, you can always use the system's page memory allocator (for example VirtualAlloc on Win32), and if the system respects the no-execute bit or allows read/write/execute memory protection on pages, just make a call to change the memory protection (for example VirtualProtect on Win32). Of course, there are plenty other ways to do this, but on the lower level, it will always involve allocing a piece of memory which can contain executable code. The real problem here is generating the right code which points to the right (closure data) offsets (apply relocations if needed or generate base indepdent code).

2) does not work because your funcall macro can't be passed around as a function pointer. there's no real way to do it other than return a struct (the closing environment) and pass in that struct in the function call.
You'd pass a "function object"(encapsulates a function and the closure object) to the funcall macro. The macro itself calls the function field of the structure with the closure object and the rest of the arguments passed. It can also be done as a function. While this means that you're passing structs around instead of function pointers, and the syntax is a bit different, the functionality is achieved, except it's not nearly as comfortable to use as normal functions.

Closures are probably a pain to use in languages which don't support them natively, maybe to the point you might not want to bother with them.

>>83
How do we know when the closure object will be freed? Most code is usually freed by the OS when the application exits, however that's probably not a good idea for closures as they can grow in number. Given C's approach of manual memory management, you'd probably make some closure_free function which performs the cleanup and call it whenever you don't need the closure anymore.

Name: Anonymous 2010-07-18 20:05

Object pascal:


type
 TNumFunc = function(i: PtrInt): PtrInt of object;
 
 TNumHax = class
  function NumFunk(i: PtrInt): PtrInt;
 end;

function TNumHax.NumFunk(i: PtrInt): PtrInt;
begin
   result := PtrInt(self)+i;
end;

function foo(n: PtrInt): TNumFunc;
begin
   TMethod(result).Code := @TNumHax.NumFunk;
   TMethod(result).Data := Pointer(n);
end;

Name: Anonymous 2010-07-18 21:11

-- I love Haskell
f = (+)

Name: Anonymous 2010-07-18 21:36

I have to say, I'm disappointed at the severe lack of ridiculous implementations.

Name: Anonymous 2010-07-18 21:36

>>85
Yes but your macro can't be used as a function pointer, that's the whole point. You can't pass it around as an int(*)(int). You're not calling the return value of the generator as a function; you're calling some other macro, passing in the return value of the generator.

This is why you can almost accomplish this in C++ by creating an object containing the closure values and overriding operator(). You can't store it in a regular function pointer, but you can still call it as a regular function.

Name: Anonymous 2010-07-18 21:42

>>89
You can't store it in a regular function pointer, but you can still call it as a regular function.
That's similar to >>21 in that you have to call() the returned block, you can't just invoke it like a method.

Name: Anonymous 2010-07-18 21:43

>>88
Don't make me bust out the.. uh.. Tcl.

Name: Anonymous 2010-07-18 22:23

>>90
Actually, it should be possible to generate a small function which calls a specific closure, and you only have to specify the closure params to it. Easy with a bit of asm, but not very portable. That's the problem with languages which can't generate code at runtime and can't assign symbols with code at runtime. Much easier done in Lisp.

Name: Anonymous 2010-07-18 22:23

>>90
Actually, it should be possible to generate a small function which calls a specific closure, and you only have to specify the closure params to it. Easy with a bit of asm, but not very portable. That's the problem with languages which can't generate code at runtime and can't assign symbols with code at runtime. Much easier done in Lisp.

Name: Anonymous 2010-07-18 23:20

>>92
>>21 could be 'fixed', but it wouldn't normally be worth the extra code. Sending a call message is not a serious problem. Fixing the C++ example is certainly not worth it, and any attempts to do so trade on the purity of the concept anyway.

Name: Anonymous 2010-07-18 23:37

I use closures in C all the time.  Also, typedefs are for pussies.


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int (*mkadder(int n))(int i)
{
    static const unsigned char TEXT[13] = {
        0x55, 0x89, 0xe5, 0x8b, 0x45, 0x08, 0x5d, 0x05, 0, 0, 0, 0, 0xc3
    };
    unsigned char *p = malloc(13);
    if (!p) return NULL;
    memcpy(p, TEXT, 13);
    memcpy(p + 8, &n, 4);
    return (int (*)(int))p;
}

int main(int argc, char *argv[])
{
    int (*f)(int), (*g)(int);
    f = mkadder(10);
    g = mkadder(100);
    printf("f(5) = %i\n", f(5));
    printf("g(16) = %i\n", g(16));
    return 0;
}

Name: Anonymous 2010-07-18 23:40


def foo(n):
    return lambda i:n+i

Name: Anonymous 2010-07-18 23:46

>>69

You started with Haskell just a few days ago?  That much is obvious, no Haskeller with more than a week's experience would write such verbose code.


foo :: (Num a) => a -> a -> a
foo = (+)

Name: Anonymous 2010-07-19 0:01

>>97
verbose code.
foo :: (Num a) => a -> a -> a

HIBT?

Name: Anonymous 2010-07-19 2:31

>>95
You just bumped into my NX bit

Name: Anonymous 2010-07-19 3:04

>>98
No, you are just an idiot.

Name: Anonymous 2010-07-19 3:15

>>95
I love you.
>>99
Fuck your shit.

Name: Anonymous 2010-07-19 3:22

I have NX bit turned by default and immutable.
Any "clever" program trying to write/execute to memory(like some Opera versions) gets uninstalled immediately.
Such hacks have no place in modern enterprise environment.

Name: Anonymous 2010-07-19 3:25

>>102
Java and any JIT/VM/Intepreter engines requires executing memory. Are you saying your enterprise doesn't work with Java EE?

Name: Anonymous 2010-07-19 3:28

>>103
His "ENTERPRISE" is his basement, and it involves a huge wall poster of Captain Picard and his lackeys.

Name: Anonymous 2010-07-19 3:33

>>103
Since only idiots use Java, why are you even mentioning it?
Are you an idiot?

Name: Anonymous 2010-07-19 3:42

>>103

I'm going to go ahead and agree with #103, even for non-JIT interpreted environments.  The only difference is that non-JIT interpreted environments aren't affected by the NX bit, because the NX bit can only stop regions of memory from being executed by the processor itself.  The same types of attacks that work on buffer overflows in native code foiled by the NX bit would succeed against the same flaws in interpreted environments.

So that means that #102 should, by their own admission, remove any copies of Perl / Python / Ruby / Java / Javascript / Lisp / Scheme / Haskell / Bash / Sh / Zsh / Ksh / Apple BASIC from their systems right now.  Doubly so for Java / Python "Unladen Swallow" / Lua-JIT / half of Lisp implementations ever.

It's not "clever", it's the whole point of the Von Neumann architecture.  If people thought we didn't need to execute main memory, we'd switch to Harvard architecture in a heartbeat -- processor performance certainly increases.  But no, people only use Harvard architecture for dumb, fast things like DSP microcontrollers.

Enforcing the NX bit on all your programs' heaps is like trying to reduce home burglaries by nailing everyone's windows shut.

Name: Anonymous 2010-07-19 3:52

Program A creates binary file B and saves it to disk/ram
B executes/spawns as new thread/process/dll.
NX bit just stands there being useless.
Where is your Neumann now?

Name: Anonymous 2010-07-19 4:00

>>102
That's silly and there are countless ways to bypass it. It's also harmful because it disallows dynamic code generation done by a lot of modern language implementations.

Also what >>106 said:
So that means that #102 should, by their own admission, remove any copies of Perl / Python / Ruby / Java / Javascript / Lisp / Scheme / Haskell / Bash / Sh / Zsh / Ksh / Apple BASIC from their systems right now.  Doubly so for Java / Python "Unladen Swallow" / Lua-JIT / half of Lisp implementations ever.
Enjoy your C-only setup >>102.

Did I also mention that on some platforms, executable packers/protections are prevalent and a lot of applications write code then execute it. Are you telling me you refuse to run UPX'ed apps?

Name: Anonymous 2010-07-19 4:17

<?php

// 5.3 -->
function foo_closure($n)
{
    return function($i) use ($n) {
         return $n + $i;
    };
}

// --> 5.2
function foo_createfun($n)
{
    return create_function('$i', 'return $i + ' . $n . ';');
}

Name: Anonymous 2010-07-19 4:26

On that note, here's a helpful comment from the manual. Topmost entry. Luckily I happened to glance across it.

To avoid memory problems, when creating a dynamic function within loops, register it as a global variable, and check if it has already been set;

<?php
global $my_func;
if (!isset($my_func))
{
    $my_func = create_function($args, $code);
}

$my_func();
?>

That way you don't end up creating the same function twice (or a couple of million of times, as it happened to me...)

Name: Anonymous 2010-07-19 4:48

Here's an "improved" C version, guaranteed to be portable across different Linux architectures.  It's also very easy to change the function to perform arbitrary computations.  With minimal modification it can also run on OS X.  No worries about the NX bit, either.  It does leak memory, though... like all good C programs should.


#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>

int (*mkadder(int n))(int i)
{
    FILE *tmp;
    void *lib, *func;
    int r;
    char nmc[20], nml[20], cmd[40];
    snprintf(nmc, sizeof(nmc), "./tmp%i.c", n);
    snprintf(nml, sizeof(nml), "./tmp%i.so", n);
    snprintf(cmd, sizeof(cmd), "gcc %s -shared -o %s", nmc, nml);
    if (!(tmp = fopen(nmc, "w"))) err(1, "fopen");
    fprintf(tmp, "int func(int i) { return i + %i; }\n", n);
    fclose(tmp);
    if ((r = system(cmd))) errx(1, "gcc");
    unlink(nmc);
    if (!(lib = dlopen(nml, RTLD_LAZY | RTLD_LOCAL)))
        errx(1, "dlopen: %s", dlerror());
    if (!(func = dlsym(lib, "func")))
        errx(1, "dlsym: %s", dlerror());
    unlink(nml);
    return func;
}

int main(int argc, char *argv[])
{
    int (*f)(int), (*g)(int);
    f = mkadder(10);
    g = mkadder(100);
    printf("f(5) = %i\n", f(5));
    printf("g(16) = %i\n", g(16));
    return 0;
}

Name: Anonymous 2010-07-19 4:58

>>111
gcc: not found

Name: Anonymous 2010-07-19 5:03

>>111
My!

Name: Anonymous 2010-07-19 5:20

* A new warning has been added to GCC: "-Wtrampolines".  This issues a warning message whenever gcc generates a trampoline, which is a small piece of code that is needed whenever the address of a nested function is taken.  Since this piece of code is created at run time on the stack, it requires an executable stack in order work.  This might be a problem for the target execution environment.

http://nickclifton.livejournal.com/6143.html

Name: Anonymous 2010-07-19 7:12

While I'm sure most of us love entertaining dynamic code generation, in reality, very few language implementations recompile the whole function to generate a closure (I haven't actually see any that do), instead, what they do is compile the closed over functions, and the closure state is referenced either through the stack(arguments) or through some other hidden way to pass arguments. It's also quite common to pass a reference instead of the literate value, this allows sharing the value between functions/closures. Closure objects themselves are very lightweight and only contain: tag bits (or some other way to identify them), a reference(pointer) to the function object (usually tagged as well), the closure data(array or structure(which are not that different from arrays)). Closures themselves are callable objects, just like functions (those functions objects) or other data types which can be callable (for example, funcallable instances(of classes) exist in CL implementations with MOP support, they're functionally equivalent to closures, but allow more fine-grained control)). Calling such an object would lead to either have the compiler generate the needed calling code by itself (if it's possible to determine at compile time), or call a dispatcher which performs the call at runtime depending on the type.

It should also be noticed that some of the closure implementations in this thread use literals, so they do not allow sharing state, here's a simple example which illustrates this as well as shows how the closure internals work:


(let ((a 0))
  (defun set-a (n)
    (setf a n))
  (defun get-a ()
    a))

CL-USER> (get-a)
0
CL-USER> (set-a 100)
100
CL-USER> (get-a)
100

and some internals:
#'get-a:

#<FUNCTION {24E2D435}>
--------------------
FUNCTION: #<FUNCTION GET-A {24DE7E05}>
Closed over values:
0: #<value cell 100 {24DE7C4F}>

#'set-a:

#<FUNCTION {24DE7C3D}>
--------------------
FUNCTION: #<FUNCTION SET-A {24DE7E3D}>
Closed over values:
0: #<value cell 100 {24DE7C4F}> <-- same pointer!

the value cell a:

#<SB-KERNEL::RANDOM-CLASS {24DE7C4F}>
--------------------
VALUE: 100

(In this case, the compiler actually compiles both functions at once, so they actually point to different offsets within the same code block, but that'd be too much detail to show here...)

Also keep in mind that while this used functions, closures can be generated at runtime quite easily and cheaply (just return a lambda), so whatever closure implementation your language supports needs to allow this as well (without the previous requirement, you can just use globals to achieve the same).

So the points I'm trying to make is that real closures:
1) Allow their value to be shared by other closures or pieces of code. They can close over anything in the lexical scope. Sharing values also means that if the language allows mutation of variables, this should also be supported.
2) Can be implemented fairly cheaply(in terms of speed and space cost) without the need of runtime code generation.

Sadly, I don't see how you can achieve these goals in ANSI C portably without adding your own function call macro, which would make everything quite clunky, also memory management would be a pain.

Name: Anonymous 2010-07-19 8:14

>>115

Most of the people who would do this kind of thing in C are people who are implementing runtime libraries for higher level languages, and they don't care about portability because they'd need to rewrite the code generator if they switched architectures anyway.

To summarize the reasonable options presented in #115, implementors have three reasonable options for supporting closures:

1. Use globals and only allow one instance of a given closure to be active at any given time.  This works surprisingly well on the smallest of embedded systems.  Some environments for small embedded systems don't support recursive functions.  By "small", I mean no more than 1K RAM.
2. Change the calling convention for functions, add a "hidden" parameter.
3. Dynamically generate a piece of code to add a hidden parameter to the function call and then jump to the main function.

I'm making a case for #3 as being pretty reasonable.  Runtime code generation sounds like a beast, but on most architectures you can write one piece of glue code that works for all closures.  It would only require twenty bytes or so, and for most runtimes you'd need to make an allocation for technique #2 anyway so an extra twenty bytes is pretty cheap.  In many cases a sophisticated complier would inline the glue code (if its value is known) which effectively turns it into case #2.  (This glue code is what GCC calls a "trampoline".)  The performance question boils down to which you do more often: pass around closures or ordinary function pointers.  My guess is that:


; Assuming mapcar isn't inlined.  This assumption is almost certainly wrong.
(mapcar #'car my-list) ; faster with option #3, probably
(mapcar #'(lambda (x) (* x n)) my-list) ; faster with option #2, probably
; Do you even know which of the above two cases is more common for non-inlined
; higher order functions in your code base?  I bet you have no clue.
; So the performance argument is kinda pointless.


As for C, these days you can use blocks if you're okay with targeting clang.  That's not unreasonable, people writing Lisp code are fairly cavalier about portability and most Haskellers you meet don't care about any compiler other than GHC.

Name: Anonymous 2010-07-19 9:08

>>111
To optimize speed just write it to a RAM drive.

Name: Anonymous 2010-07-19 9:44

>>117

That shouldn't result in much of a speed difference, if any.  Do you even know what the page cache is?

Name: Anonymous 2010-07-19 11:17

>>118
You don't appear to.

Name: Anonymous 2010-07-19 11:43

>That shouldn't result in much of a speed difference, if any.
Windows designer detected.

Name: Anonymous 2011-12-02 13:32

>>122
nice doubles bro

Name: Anonymous 2011-12-02 13:35

>>121
faggot

Name: Anonymous 2011-12-02 15:34

>>80
eval? What? Why?


sub f {
    my $a = shift;
    return sub { return $a + shift; };
}


It's not like having to dereference the sub with a -> is a big deal anyway.

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