Programming "only" in an environment of C and it's friends - Being a toolsmith

S

Stefan Ram

Ian Collins said:
Not all applications require speed.

Java seems to offer a good trade-off between the speed of writing code
and the speed of running code. One can code faster because of the GC and
other features, and at the same time it possibly is the fastest language
with a GC. About 32 times faster than Perl, but only 1.31 times slower
than C++, according to:

http://shootout.alioth.debian.org/u32/which-programming-languages-are-fastest.php
http://shootout.alioth.debian.org/u64q/java.php
 
G

Guest

On Monday, May 28, 2012 12:47:26 PM UTC+1, Stefan Ram wrote:

When one does some »AI-style« programming with a graph where
multiple objects link to each other in a very dynamic way,
memory management can become hard, so this is also easier to
code in GC languages.

Expressions in functional languages often involve transfer of
ownership or sharing of ownership of run-time allocated objects
and can't really be written in C.

why not? really, why not? I'm actually trying to implement one such languages and I don't see why C makes it necessarily hard to do
Apart from some simple cases,
one cannot write in a pure functional style in C.

why not?
One can »emulate« OOP in C, but it sometimes needs some more
complicated wording.

encapsulation, easy. polymorphism is a bit harder. You can do some nasty things with structs but I'm not sure it's worth it. Could you do some sort ofDuck Typing?
The need for manual memory management can
become distracting.

yes, but I'm so used to it C its just sort of there in the background.
So, C is a »multi-paradigm« language only to some extend.

I'm not convinced. You're back to Turing Completness. I'm sure I could write a functional program in COBOL- but would I enjoy it?
 
B

BartC

On Monday, May 28, 2012 12:47:26 PM UTC+1, Stefan Ram wrote:



why not? really, why not? I'm actually trying to implement one such
languages and I don't see why C makes it necessarily hard to do

Maybe the difference is between writing such code directly in C, and
implementing such code in another language, in C.
 
S

Stefan Ram

why not? really, why not? I'm actually trying to implement
one such languages and I don't see why C makes it necessarily
hard to do

I was not talking about using C to /implement/ a pure
functional language (PFL), but about using C to write in a
pure functional manner in C itself (i.e., using C as a PFL).

In »print(eval(input()))«, eval() is supposed to return a
meaningful value, which in a PFL has to have the type of the
image of the function »eval«. In all but the most simple
cases, such a value is a dynamically allocated graph.

When we write this in C: How should »eval« behave, when
a called »malloc« returns 0? The usual good practice in C
is to report such a failure to the caller. But the return
value of »eval« already has another meaning.

Moreover, when should the graph allocated by »eval« be
deallocated again? In »print«? But what should one then
call the next time one wants to print a value /not/
deallocating it?

So the need to check allocation attempts and to manage
dynamic memory in C makes such wording as
»print(eval(input()))« difficult in C.

Also, in C, blocks are not functions, so one lacks
function literals (anonymous functions) in C and
one also lacks lazy evaluation of arguments (see below).
encapsulation, easy. polymorphism is a bit harder. You can do
some nasty things with structs but I'm not sure it's worth
it. Could you do some sort of Duck Typing?

You can do everything you can imagine, but when using it
in C itself, the wording might be more complicated. In a
pure object-oriented language (POOL), even blocks are
objects, so, in Smalltalk, one can implement a custom if
statement with a custom boolean type that can be used as

a > 0 ifTrue: [a := 0]

. This will set »a := 0« if a > 0. In C, one cannot write

( greater( a, 0 )->ifTrue )({ a = 0; })

since blocks are not expressions, one would need to write

( greater( a, 0 )->ifTrue )( set( a, 0 ))

using a function call. But since, in C, arguments are
evaluated always, this would always set a to 0. We don't
have lazy evaluation in C for function arguments. This
also applys to the question of writing in a PFL style
in C. (PFLs and POOLs have some thinks in common.)

Moreover, »greater( a, 0 )« was assumed to return a
structure with a function pointer »ifTrue«, that needs to be
allocated dynamically. This also raises the question how it
should report a failure due to lack of memory and how that
memory should be managed after a successful allocation.
 
G

Guest

I was not talking about using C to /implement/ a pure
functional language (PFL), but about using C to write in a
pure functional manner in C itself (i.e., using C as a PFL).


In »print(eval(input()))«, eval() is supposed to return a
meaningful value, which in a PFL has to have the type of the
image of the function »eval«. In all but the most simple
cases, such a value is a dynamically allocated graph.

not all functional languages are dynamically typed
When we write this in C: How should »eval« behave, when
a called »malloc« returns 0? The usual good practice in C
is to report such a failure to the caller. But the return
value of »eval« already has another meaning.

Moreover, when should the graph allocated by »eval« be
deallocated again? In »print«? But what should one then
call the next time one wants to print a value /not/
deallocating it?

So the need to check allocation attempts and to manage
dynamic memory in C makes such wording as
»print(eval(input()))« difficult in C.

Also, in C, blocks are not functions, so one lacks
function literals (anonymous functions) in C and
one also lacks lazy evaluation of arguments (see below).
encapsulation, easy. polymorphism is a bit harder. You can do
some nasty things with structs but I'm not sure it's worth
it. Could you do some sort of Duck Typing?

You can do everything you can imagine, but when using it
in C itself, the wording might be more complicated. In a
pure object-oriented language (POOL), even blocks are
objects, so, in Smalltalk, one can implement a custom if
statement with a custom boolean type that can be used as

a > 0 ifTrue: [a := 0]

. This will set »a := 0« if a > 0. In C, one cannot write

( greater( a, 0 )->ifTrue )({ a = 0; })

since blocks are not expressions, one would need to write

( greater( a, 0 )->ifTrue )( set( a, 0 ))

using a function call. But since, in C, arguments are
evaluated always, this would always set a to 0. We don't
have lazy evaluation in C for function arguments. This
also applys to the question of writing in a PFL style
in C. (PFLs and POOLs have some thinks in common.)

Moreover, »greater( a, 0 )« was assumed to return a
structure with a function pointer »ifTrue«, that needs to be
allocated dynamically. This also raises the question how it
should report a failure due to lack of memory and how that
memory should be managed after a successful allocation.

thanks!
 
R

Rui Maciel

Stefan said:
Java seems to offer a good trade-off between the speed of writing code
and the speed of running code. One can code faster because of the GC and
other features, and at the same time it possibly is the fastest language
with a GC. About 32 times faster than Perl, but only 1.31 times slower
than C++, according to:

http://shootout.alioth.debian.org/u32/which-programming-languages-are- fastest.php
http://shootout.alioth.debian.org/u64q/java.php

I would argue that Java's problem isn't necessarily how slow it might be on
some benchmark, but how responsive Java programs might appear to the user.
I've noticed that, when compared to some GUI applications developed in, say,
C++, Java apps present a noticeable lag. This tends to degrade the user
experience.

Granted, this might not have anything to do with the Java language and
everything to do how specific programs are developed.


Rui Maciel
 
B

BartC

Stefan Ram said:
(e-mail address removed) writes:
You can do everything you can imagine, but when using it
in C itself, the wording might be more complicated. In a
pure object-oriented language (POOL), even blocks are
objects, so, in Smalltalk, one can implement a custom if
statement with a custom boolean type that can be used as

a > 0 ifTrue: [a := 0]

. This will set »a := 0« if a > 0.

In other words, if (a>0) a=0;
In C, one cannot write

( greater( a, 0 )->ifTrue )({ a = 0; })

since blocks are not expressions, one would need to write

( greater( a, 0 )->ifTrue )( set( a, 0 ))

Perhaps you need a more elaborate example where there isn't a trivial way of
doing it in C...
using a function call. But since, in C, arguments are
evaluated always, this would always set a to 0. We don't
have lazy evaluation in C for function arguments.

C has function pointers. Those are only evaluated on demand. Of course, any
parameters have to be supplied separately, and the body of the function that
is pointed to - the code to be executed on demand- has to be written
elsewhere.

So it's somewhat untidy and makes it harder to follow. But then, I can
imagine that code full of conditional block objects that may or may not have
been executed yet, sounds pretty complicated too.
Moreover, »greater( a, 0 )« was assumed to return a
structure with a function pointer »ifTrue«, that needs to be
allocated dynamically. This also raises the question how it
should report a failure due to lack of memory and how that
memory should be managed after a successful allocation.

I can't see that being a real issue. If this is is supposed to be a higher
level language, that you don't really want to be thinking about that stuff
at this level. It needs to be taken care of elsewhere. Otherwise the code is
going to be impossible and lose any advantage of the functional style.

(As a matter of interest, what does Smalltalk do when the program runs out
of memory for objects? If errors can be trapped by the user program, how
useful is that inside a deeply nested piece of code?)
 
M

Malcolm McLean

בת×ריך ×™×•× ×©× ×™,28 במ××™ 2012 15:25:49 UTC+1, מ×ת Bart:
Perhaps you need a more elaborate example where there isn't a trivial wayof
doing it in C...
Write a function which takes a function foo() as a parameter, and as an output returns a function which is identical to foo(), except where foo() produces nan on divide by zero, creates a very high value instead.
 
S

Stefan Ram

BartC said:
I can't see that being a real issue. If this is is supposed to be a higher
level language, that you don't really want to be thinking about that stuff
at this level. It needs to be taken care of elsewhere. Otherwise the code is
going to be impossible and lose any advantage of the functional style.

Therefore, the host language should have a GC.

(I forgot to mention that in

print(eval(input()))

, »print« just can't deallocate the graph obtained from »eval«,
since it does not know whether parts of that graph are shared with other
owners. So some kind of GC or global memory management is necessaary.)
(As a matter of interest, what does Smalltalk do when the program runs out
of memory for objects? If errors can be trapped by the user program, how
useful is that inside a deeply nested piece of code?)

I don't know. Maybe execution is based on the assumption that this will
always work, and is interrupted or aborted otherwise.

In Java, a run-time error is thrown that can be caught and handled.
This sounds hard, but I used this once: The handler first released some
memory set aside for this case and then was able to handle the situation
using this memory.

In C, the classical high-quality coding style is to check the result
of every malloc, fopen, ... and to act accordingly. However, sometimes
it already solves a problem at hand to assume success of all such calls
and not even explicitly free() allocated memory, again.

Maybe, one /can/ check too much, e.g.,

if( printf( "abc\n" )!= 4 )
{ if( fprintf( stderr, "printf failed!\n" )!= 15 )
{ /* now, what? ...
 
B

BartC

Malcolm McLean said:
בת×ריך ×™×•× ×©× ×™, 28 במ××™ 2012 15:25:49 UTC+1, מ×ת Bart:
Write a function which takes a function foo() as a parameter, and as an
output returns a function which is identical to foo(), except where foo()
produces nan on divide by zero, creates a very high value instead.

That sounds near impossible, in whatever language. Assuming you aren't
talking about a foo() merely returning a different floating point result,
but one that may or may not include floating point operations, and if it
does, then to alter the nature of all floating point operations executed
while in the lexical scope of foo()'s replacement.
 
S

Stefan Ram

Malcolm McLean said:
Write a function which takes a function foo() as a parameter,
and as an output returns a function which is identical to
foo(), except where foo() produces nan on divide by zero,
creates a very high value instead.

(I suggest to start reading at the function »main« at the
bottom of the program.)

#include <stdio.h>

struct concatenation
{ int tag;
struct function * f;
struct function * g; };

struct function
{ int tag;
double( *f )( double const x ); };

struct abstract_function
{ int tag; };

double eval( struct abstract_function const * const f, double const x )
{ return( f->tag == 1 )?(( struct function * )f)->f( x ):
eval
( ( struct abstract_function * )( (( struct concatenation * )f)->f ),
eval
( ( struct abstract_function * )((( struct concatenation * )f )->g ), x )); }

struct function const * const new_function( double( *f )( double const x ))
{ struct function * function = malloc( sizeof( struct function ));
if( function )
{ function->tag = 1;
function->f = f; }
return function; }

struct function const * const new_concatenation
( struct abstract_function const * const f,
struct abstract_function const * const g )
{ struct concatenation * concatenation = malloc( sizeof( struct concatenation ));
if( concatenation )
{ concatenation->tag = 2;
concatenation->f = f;
concatenation->g = g; }
return concatenation; }

double const reciprocal( double const x ){ return 1/x; }

double const infto99( double const x ){ if( x == 1./0 )return 1e99; else return x; }

struct abstract_function const * const wrap_with_infto99
( struct abstract_function const * const g )
{ return new_concatenation( new_function( infto99 ), g ); }

int main( void )
{ struct abstract_function const * const reciprocal_function
= new_function( reciprocal );
if( reciprocal_function )
{ struct abstract_function const * const wrapped_reciprocal_function
= wrap_with_infto99( reciprocal_function );
if( wrapped_reciprocal_function )
{ printf( "%g\n", eval( wrapped_reciprocal_function, 0 ));
free( wrapped_reciprocal_function ); }
free( reciprocal_function ); }}
 
I

Ian Collins

Java seems to offer a good trade-off between the speed of writing code
and the speed of running code. One can code faster because of the GC and
other features, and at the same time it possibly is the fastest language
with a GC. About 32 times faster than Perl, but only 1.31 times slower
than C++, according to:

For the types of application I listed, the load time and memory
footprint for Java is the killer. Even Sun removed Java from their OS
installer because it was a resource hog.
 
K

Keith Thompson

in writing computer code, the language C has obvious advantages over
other languages ("fads"): [...]
It's perfect for operating system interfacing.

I think taht's a bit of a coincidence

It's hardly a coincidence for those operating systems that are
implemented in C.
 
K

Keith Thompson

Malcolm McLean said:
בת×ריך ×™×•× ×©× ×™, 28 במ××™ 2012 10:16:53 UTC+1, מ×ת Bart:
tcc (tiny C compiler) has an intepreted mode. If you just give your C
script a shebang (#! /usr/bin/tcc in the first line) it can run as a
Linux / Unix shell script.

Actually the shebang needs to be "#!/usr/bin/tcc -run".

BTW Malcolm, it would be helpful if you could format your posts in, say,
72-column lines. Not all newsreaders wrap long lines gracefully.
 
K

Keith Thompson

perl -p -i -e 's/a/b/g' *

will replace all occurrences of the regular expression »a«
with the pattern »b« in all of the files in the current
directory. Now show me that in C! There is not even a
portable way to read a directory in C.
[...]

True, and Perl can read directories -- but in the above snippet
the directory reading is done by the "*", i.e. by the shell used
to invoke the perl command.
 
K

Keith Thompson

Malcolm McLean said:
בת×ריך ×™×•× ×©× ×™, 28 במ××™ 2012 15:25:49 UTC+1, מ×ת Bart:
Write a function which takes a function foo() as a parameter, and as
an output returns a function which is identical to foo(), except where
foo() produces nan on divide by zero, creates a very high value
instead.

Turing equivalence applies to programs, not to functions.

Suppose you have a program in some language where functions are
first-class objects, and that program includes a function like the one
you describe.

You can't necessarily duplicate that function in C, but you
can duplicate the behavior of the whole program in a C program.
(If nothing else, you can write an interpreter in C.)
 
M

Malcolm McLean

בת×ריך ×™×•× ×©× ×™,28 במ××™ 2012 21:04:31 UTC+1, מ×ת Keith Thompson:
BTW Malcolm, it would be helpful if you could format your posts in, say,
72-column lines. Not all newsreaders wrap long lines gracefully.
I need to sack Google groups. Abnyone suggest a betters newsreader?
 
J

James Kuyper

On 05/29/2012 05:55 AM, Malcolm McLean wrote:
....
I need to sack Google groups. Abnyone suggest a betters newsreader?

I like Mozilla Thunderbird, but it requires you to set up a connection
to an actual news server. I strongly recommend news.eternal-september.com.
 
G

Guest

On 05/29/2012 05:55 AM, Malcolm McLean wrote:
...

I like Mozilla Thunderbird, but it requires you to set up a connection
to an actual news server. I strongly recommend news.eternal-september.com.

how does that do on a small screen (eg. Blackberry)?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top