Functions and functional programming.

Discussion in 'C Programming' started by Malcolm McLean, Jun 2, 2014.

  1. If you've got a convention that error shall always be a pointer and
    shall always be the last parameter, it's best to stick to it.
    The convention has some value when functions naturally return a
    result, in some libraries results are returned through pointers,
    purely to preserve the convention that the return type shall be
    the error status.
    Malcolm McLean, Jun 4, 2014
    1. Advertisements

  2. The parameter `error' is an output parameter so it must point to a valid
    location which is always written to.
    I don't understand what you mean here.
    It is common practice to initialize an output parameter like this to
    either zero or one depending on whether successful or unsuccessful paths
    dominate the implementation.

    -- August
    August Karlstrom, Jun 4, 2014
    1. Advertisements

  3. Malcolm McLean

    Ike Naar Guest

    What is the difference between an application and a real world application?
    Can you name an application that is not a real world application?
    Ike Naar, Jun 4, 2014
  4. Malcolm McLean

    Ike Naar Guest

    If the 'ptr=NIL;' assignment is not meant to be a manual GC request,
    then what would be the reason to perform the assignment at all?
    Remember we're talking about an assignment that might be optimized
    away (see elsethread), which gives the impression that it apparently
    serves no other purpose than to trigger garbage collection.
    Ike Naar, Jun 4, 2014
  5. Malcolm McLean

    Jorgen Grahn Guest

    C doesn't have output parameters, so that would have to be a
    (documented) convention. I have personally used all three variants he
    lists (may be NULL, indicates error/no error, accumulates errors) but
    I had to choose and then document carefully.
    I think he's talking in a C context. For one thing, such a construct
    is almost unheard of in C. You said it yourself upthread --
    C programmers generally don't accept that principle you're following.

    Jorgen Grahn, Jun 4, 2014
  6. Malcolm McLean

    Melzzzzz Guest

    GC is problematic on large heaps, that is causes non stop swapping.
    That is why it is not advisable to use GC at virtual machines.
    Other thing is that non blocking GC-s require much more processing
    time than stop the world collectors. Eg IBM concurrent collector
    requires complex access to pointer/reference - that is membar and
    some pointer chasing...
    Melzzzzz, Jun 4, 2014
  7. Malcolm McLean

    jacob navia Guest

    Le 04/06/2014 21:35, Malcolm McLean a écrit :
    In the containers library I used another convention. Error return (an
    integer mostly) in the result, and parameters by pointers.

    Functions that return pointers are also boolean: either it is a valid
    pointer or NULL. Obviously when ANY error happens, the standard
    callbacks are called, before any other action.

    The library comes with default callbacks that put something in stderr
    and go on.

    The library user can change this as he/she wants by changing the
    callbacks and putting other functions.


    int errorCode = Interface.functionXXX(Object *,...);

    Positive: OK
    Zero: OK with warnings
    Negative: hard error

    if (List.Append(memberslist,newSubscriptions ) >= 0)
    // OK;
    else return NULL;

    To do:

    Extensible. You should be able to add your own error types to the table.
    I think that a utility could inspect the executable between two UUIDs,
    modifying parameters in the style:

    What do you want to do

    when there is no more memory?
    When a bad pointer is discovered?
    Array bounds exceeded?
    Other internal inconsistencies?

    Do you want to log all errors?
    If yes where (path)?

    Binary layout would be:

    static uuid start = { };
    /* Modifiable parameters */
    size_t size;
    char strict=0; // Go on by default
    .... // Other parameters
    statuc uuid end = { };

    The size data field means the number of bytes to skip to find the end uuid.

    A simple utility scans the executable for the start uuid, reads the size
    parameter, skips that number of bytes and verifies that the end uuid is
    also there.

    Now, the default callback of the no memory error would look at the value
    of strict. If non zero it will exit the program. Other callbacks may or
    may not follow that convention.

    This gives great flexibility to classify errors. For instance some
    memory-hog program crashes but the main programis not affected, it is an
    optional functionality, available only when more memory is there.
    jacob navia, Jun 4, 2014
  8. Malcolm McLean

    Richard Bos Guest

    There is no such thing as an "output parameter" in C. There are only
    pointers. Pointers can be null. It is the function's documentation's job
    to declare whether this pointer _may_ also be null, or not. This is a
    very different case from real output parameters, as used in, e.g.,
    Pascal, which _cannot_ be null.
    And yes, there are real reasons to have a function where an *error
    pointer _may_ be null. And yes, there are real examples of functions
    where this is the case. strtol() does something very similar.

    Richard Bos, Jun 4, 2014
  9. Malcolm McLean

    Kaz Kylheku Guest

    Where is it declared that it's an output parameter?

    The int foo(int x) return value is obviously nothing else but an output
    from the semantics of returning.
    I.e. we are not using the return value for anything and have made it void, and
    then are using a pointer to return the status.

    We are ignoring the right tool for the job: the return mechanism.
    It's not common *compiler* practice to enforce this, compared to useful
    warnings related to return values.
    Kaz Kylheku, Jun 5, 2014
  10. Malcolm McLean

    Kaz Kylheku Guest

    Note that in a properly designed garbage collected language we wouldn't need
    this assignment.

    The garbage collector, somehow in cooperation with the compiler, already knows
    that ptr is a dead variable: a variable with no next use in the data flow
    graph! (For instance, the compiler might publish liveness information whereby
    for a given instruction pointer, there is a table of stack offsets where
    variables live in the current frame, and perhaps a bitmask of registers which
    contain live values. The register or memory location containing ptr is not
    listed. Or, the compiler could generate the "ptr = nil" code for dead
    variables, and somehow mark it so that later optimizations don't remove it.)

    So, yes, this assignment this is a manual "something". It's not exactly a GC
    request because it doesn't necessarily end the lifetime of the object,
    nor does it trigger GC. It's a manual attempt way to propagate the end-of-life
    of the variable to GC.

    Except that it doesn't work without some additional trick due to the
    optimization that is carried out without any GC integration.
    Yes; it is written in hopes that if ptr has the last reference then
    the object becomes garbage.
    Kaz Kylheku, Jun 5, 2014
  11. Malcolm McLean

    Kaz Kylheku Guest

    Without massive qualifications, this is simply nonsense.

    "Virtual machine" is not the same as "virtual memory". (Why wouldn't
    you use GC on a virtual machine that is fully backed by adequate RAM.)

    Generational GC avoids making passes over old data that wastefully confirm that
    old data that was previously reachable is still reachable.
    You don't get something for nothing.

    Here, we can make the broad observation that there is a tradeoff between
    achieving low latency and high throughput.

    If a system's throughput is well optimized, you will hardly be able to
    improve its latency without giving up some throughput, and vice versa.
    Kaz Kylheku, Jun 5, 2014
  12. Even an ideal garbage collector and compiler cannot always prove that a
    object is never referenced again, especially if the reference is in a
    static or global variable.

    And current garbage collectors and compilers are far from ideal. For
    instance, many garbage collectors can't free circular references; you
    have to clear one of the references for the circle to be collected.
    Exactly, plus it may also convey information to other programmers, even
    if it's not useful to the GC system (or future, better GC systems).

    Stephen Sprunk, Jun 5, 2014
  13. It is semantically an output parameter in the same sense that the return
    value of the previously mentioned `int foo(int x)' is semantically an
    error flag.
    In my opinion the return mechanism is the right tool for the job only
    when we are writing a pure (side effect free) function. To me there is
    something inherently ugly about expressions with side effects. They also
    make it harder to reason about program correctness.

    -- August
    August Karlstrom, Jun 5, 2014
  14. if( foo(x, y, z) == 0)

    Looks like it ought to be replaceable by


    or, more subtly

    if(foo(x, z, z) == 0 || bar(x, y, z) == 0)

    looks like it ought to be replaceable with

    if (bar(x, y, z) == 0 || foo(x, y, z) == 0)
    Malcolm McLean, Jun 5, 2014
  15. Malcolm McLean

    Kaz Kylheku Guest

    Indeed, it is specifically reference counting which has that problem.

    To recognize reference counting as a form of GC is to be charitably
    Kaz Kylheku, Jun 5, 2014
  16. Malcolm McLean

    Rosario193 Guest

    not if foo() change some global variable that bar() use...
    not if foo() change some global variable that bar() use...
    Rosario193, Jun 5, 2014
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.