The Forum for Discussion about The Third Manifesto and Related Matters

You need to log in to create posts and topics.

Proposal for a Functional D

12

The following changes are proposed to evolve the current imperative TTM/D into a functional form.

  1. A database is a value of a type comprising a collection of named relational values.
    1. Any reference to a relvar is taken to be a reference to an immutable relational value in a database value.
    2. Relvars may be public, application private or system (catalog).
  2. A program in D is written as a read-only operator with a database value of some type as a parameter, and returning a database value of that type as its result.
    1. Read-only access to the values of additional databases is permitted but not required.
    2. Read-only access to the value of the same database at an earlier point in time is permitted but not required.
    3. A query program should return the value of its database parameter as its result.
    4. An update program should return a new database value, and when invoked again should expect to receive a database value that may include changes by others.
  3. The selector for a new database value succeeds atomically only if its database constraint is satisfied.
    1. Shorthands similar to INSERT, DELETE and UPDATE might be useful in the creation of a new database value.
    2. Defining or deleting persistent types, operators and constraints form part of creating the new database value.
  4. A program is permitted to accept input and produce output and to retain private internal state, which may include private persistent state, by unspecified means.
  5. Update operators are permitted but not required.
  6. Assignment in any form (such as destructive, multiple, pseudo-variable) is permitted but not required.
  7. There are no transactions. The database value provided is immutable and non-varying.

Notes:

  1. Means for creating a new database value with most relvar values unchanged and some modified should be computationally inexpensive, with any physical updates taking place after the program has returned. A copy of a database value is not a copy of the physical contents.
  2. A program intending to apply a series of updates might well use private persistent state to do so.
  3. Obtaining the value of the database at an earlier point in time and returning that is equivalent to a rollback/undo.

Andl - A New Database Language - andl.org

Perhaps relevant: https://forum.thethirdmanifesto.com/forum/topic/fp-ttm-and-d-was-new-implementation/

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org
Quote from dandl on December 7, 2019, 2:50 am

The following changes are proposed to evolve the current imperative TTM/D into a functional form.

You'll need to explain first why you haven't chosen a monadic (or at least continuation-passing) style to represent updating the database. I don't find your proposal is in a 'functional form'.

  1. A database is a value of a type comprising a collection of named relational values.
    1. Any reference to a relvar is taken to be a reference to an immutable relational value in a database value.
    2. Relvars may be public, application private or system (catalog).

Can I assign the current value of some relvar (or the whole dbvar) to a program-local variable? Can I then update the database and COMMIT, making the update visible to other users/applications? Can I then re-assign the program-local value back to the relvar? IOW destroy history? What did I just do to other users/applications?

  1. 2. A program in D is written as a read-only operator with a database value of some type as a parameter, and returning a database value of that type as its result.

Nope won't work. Updates that change the schema (or constraints) produce a db value of a different type. The monadic/continuation-passing style deliberately allows for type-changing 'update'. (Update in scare quotes, because the source code looks like familiar imperative assignment, but is producing a fresh variable-binding, potentially of a different type.)

    1. Read-only access to the values of additional databases is permitted but not required.
    2. Read-only access to the value of the same database at an earlier point in time is permitted but not required.
    3. A query program should return the value of its database parameter as its result.
    4. An update program should return a new database value, and when invoked again should expect to receive a database value that may include changes by others.

Put b. and d. together, you have a recipe for banjaxing any application: a database value from some point in history is not consistent with a current value that includes "changes by others". Not consistent in the sense if you tried to merge those values, it would violate declared constraints. Monadic/continuation-passing style insists (by the mechanism of representation-hiding) that your program can't access the internals of the database type, and so can't draw components from potentially-inconsistent database states. You can only access the database (for read or update) via methods that encapsulate the internals. In that respect, it's a lot like OOP private types.

  1. 3. The selector for a new database value succeeds atomically only if its database constraint is satisfied.
    1. Shorthands similar to INSERT, DELETE and UPDATE might be useful in the creation of a new database value.
    2. Defining or deleting persistent types, operators and constraints form part of creating the new database value.
  2. 4. A program is permitted to accept input and produce output and to retain private internal state, which may include private persistent state, by unspecified means.

Nope. See above re destroying history. All state must be represented in one and only one way, viz. by being part of the value passed in the continuation. 'Update' to the db must sync with updates to other external resources, such as sending a message/screen to the user.

  1. 5. Update operators are permitted but not required.
  2. 6. Assignment in any form (such as destructive, multiple, pseudo-variable) is permitted but not required.
  3. 7. There are no transactions. The database value provided is immutable and non-varying.

Notes:

  1. Means for creating a new database value with most relvar values unchanged and some modified should be computationally inexpensive, with any physical updates taking place after the program has returned. A copy of a database value is not a copy of the physical contents.
  2. A program intending to apply a series of updates might well use private persistent state to do so.
  3. Obtaining the value of the database at an earlier point in time and returning that is equivalent to a rollback/undo.

No you can't privately rollback/undo a shared resource. Just as you can't 'push back' a line read from a console. Your application must request a fresh update, with (hopefully) the effect of returning the db content to status quo ante -- subject to that being consistent with other updates (from other users) that have happened since.

Quote from Dave Voorhis on December 7, 2019, 7:42 am

Perhaps relevant: https://forum.thethirdmanifesto.com/forum/topic/fp-ttm-and-d-was-new-implementation/

Thanks Dave, good catch. I see I explained Monadic style already.

Quote from dandl on December 7, 2019, 2:50 am
  1. The selector for a new database value succeeds atomically only if its database constraint is satisfied.
    1. Shorthands similar to INSERT, DELETE and UPDATE might be useful in the creation of a new database value.
    2. Defining or deleting persistent types, operators and constraints form part of creating the new database value.

Knee-jerk reaction to just this point:  What does "new" mean here?  We maintain that values just exist as defined members of a type.  They are independent of time and space.  A selector invocation denotes a value.

Hugh

Coauthor of The Third Manifesto and related books.
Quote from Dave Voorhis on December 7, 2019, 7:42 am

Perhaps relevant: https://forum.thethirdmanifesto.com/forum/topic/fp-ttm-and-d-was-new-implementation/

Thanks, an oldie but a goodie. Conceptually there is an 'outer block' in the database manager which performs a single destructive assignment on some 'storage in the sky'. But you are right, all I've really done is collect all the state changes into one place and thus remove a whole bunch of  complications for tracking distributed state.

Andl - A New Database Language - andl.org
Quote from AntC on December 7, 2019, 9:33 am
Quote from dandl on December 7, 2019, 2:50 am

The following changes are proposed to evolve the current imperative TTM/D into a functional form.

You'll need to explain first why you haven't chosen a monadic (or at least continuation-passing) style to represent updating the database. I don't find your proposal is in a 'functional form'.

You should get out more, you're just seeing everything through a Haskell fog. The paradigm I've chosen can span the entire range from 'OO pretending to be FP' right through to fully functional. It enables FP, rather than demanding it.

Incidentally, this paradigm is well known in the JS world. My inspiration includes Flux, Redux and Elm, not Haskell.

  1. A database is a value of a type comprising a collection of named relational values.
    1. Any reference to a relvar is taken to be a reference to an immutable relational value in a database value.
    2. Relvars may be public, application private or system (catalog).

Can I assign the current value of some relvar (or the whole dbvar) to a program-local variable? Can I then update the database and COMMIT, making the update visible to other users/applications? Can I then re-assign the program-local value back to the relvar? IOW destroy history? What did I just do to other users/applications?

Yes, no and no. There are no database updates and no COMMIT. The only thing you can do is invoke a selector to create a 'new' database value and return that as the value of your program. The database manager is responsible for making that the 'current' state of the database, and passing that value to other programs (perhaps to another invocation of your own).

  1. 2. A program in D is written as a read-only operator with a database value of some type as a parameter, and returning a database value of that type as its result.

Nope won't work. Updates that change the schema (or constraints) produce a db value of a different type. The monadic/continuation-passing style deliberately allows for type-changing 'update'. (Update in scare quotes, because the source code looks like familiar imperative assignment, but is producing a fresh variable-binding, potentially of a different type.)

Nope, it will work just fine. The database type is a permanent feature of any database and does not change when the contents change. The database selector always returns a 'new' database of a type known to the program, essentially a copy of the 'old' database to which changes are applied.

    1. Read-only access to the values of additional databases is permitted but not required.
    2. Read-only access to the value of the same database at an earlier point in time is permitted but not required.
    3. A query program should return the value of its database parameter as its result.
    4. An update program should return a new database value, and when invoked again should expect to receive a database value that may include changes by others.

Put b. and d. together, you have a recipe for banjaxing any application: a database value from some point in history is not consistent with a current value that includes "changes by others". Not consistent in the sense if you tried to merge those values, it would violate declared constraints.

Every database value is consistent with its constraints. A program that returns a historic database value will have excluded changes made by others (if any), and would usually not be permitted (that is, it would raise a security violation). I can imagine a database manager with the ability to roll back the changes made by one program and then re-apply changes made by others, much like a rebase operation in Git, but that's a different discussion.

Monadic/continuation-passing style insists (by the mechanism of representation-hiding) that your program can't access the internals of the database type, and so can't draw components from potentially-inconsistent database states. You can only access the database (for read or update) via methods that encapsulate the internals. In that respect, it's a lot like OOP private types.

Makes no sense to me, but I don't think it adds anything beyond a preoccupation with monads.

  1. 3. The selector for a new database value succeeds atomically only if its database constraint is satisfied.
    1. Shorthands similar to INSERT, DELETE and UPDATE might be useful in the creation of a new database value.
    2. Defining or deleting persistent types, operators and constraints form part of creating the new database value.
  2. 4. A program is permitted to accept input and produce output and to retain private internal state, which may include private persistent state, by unspecified means.

Nope. See above re destroying history. All state must be represented in one and only one way, viz. by being part of the value passed in the continuation. 'Update' to the db must sync with updates to other external resources, such as sending a message/screen to the user.

Yes, I did consider imposing this restriction. I think it's unnecessary in practice, but I'm open to being persuaded. But no, you can't be totally purist about this, there are practical considerations too.

  1. 5. Update operators are permitted but not required.
  2. 6. Assignment in any form (such as destructive, multiple, pseudo-variable) is permitted but not required.
  3. 7. There are no transactions. The database value provided is immutable and non-varying.

Notes:

  1. Means for creating a new database value with most relvar values unchanged and some modified should be computationally inexpensive, with any physical updates taking place after the program has returned. A copy of a database value is not a copy of the physical contents.
  2. A program intending to apply a series of updates might well use private persistent state to do so.
  3. Obtaining the value of the database at an earlier point in time and returning that is equivalent to a rollback/undo.

No you can't privately rollback/undo a shared resource. Just as you can't 'push back' a line read from a console. Your application must request a fresh update, with (hopefully) the effect of returning the db content to status quo ante -- subject to that being consistent with other updates (from other users) that have happened since.

It's actually a very tiny point. You can decide to allow or not allow side-effects as a separate policy decision.

Andl - A New Database Language - andl.org
Quote from Hugh on December 7, 2019, 4:10 pm
Quote from dandl on December 7, 2019, 2:50 am
  1. The selector for a new database value succeeds atomically only if its database constraint is satisfied.
    1. Shorthands similar to INSERT, DELETE and UPDATE might be useful in the creation of a new database value.
    2. Defining or deleting persistent types, operators and constraints form part of creating the new database value.

Knee-jerk reaction to just this point:  What does "new" mean here?  We maintain that values just exist as defined members of a type.  They are independent of time and space.  A selector invocation denotes a value.

The intent is to merely distinguish between the 'old' and 'new' database values from the program viewpoint: 'old' is passed in, 'new' is returned. Every database value is still conceptually a member of its type and the selector chooses one according to its arguments.

Andl - A New Database Language - andl.org
Quote from dandl on December 7, 2019, 11:45 pm
Quote from AntC on December 7, 2019, 9:33 am
Quote from dandl on December 7, 2019, 2:50 am

The following changes are proposed to evolve the current imperative TTM/D into a functional form.

You'll need to explain first why you haven't chosen a monadic (or at least continuation-passing) style to represent updating the database. I don't find your proposal is in a 'functional form'.

You should get out more, you're just seeing everything through a Haskell fog.

Ah you just reminded me why I left the forum once. I'll leave you to stuff this up for yourself, then.

'Monadic' is not specific to Haskell. Continuation-passing has a long pedigree [in LISP, Reynolds, Hoare] dating back well before ML, let alone Haskell.

Quote from dandl on December 7, 2019, 11:45 pm
Quote from AntC on December 7, 2019, 9:33 am
Quote from dandl on December 7, 2019, 2:50 am

The following changes are proposed to evolve the current imperative TTM/D into a functional form.

You'll need to explain first why you haven't chosen a monadic (or at least continuation-passing) style to represent updating the database. I don't find your proposal is in a 'functional form'.

You should get out more, you're just seeing everything through a Haskell fog. The paradigm I've chosen can span the entire range from 'OO pretending to be FP' right through to fully functional. It enables FP, rather than demanding it.

Incidentally, this paradigm is well known in the JS world. My inspiration includes Flux, Redux and Elm, not Haskell.

Anything "well known in the JS world" can almost certainly be dismissed. Seeing "through a Haskell fog" provides influential clarity. Much of the JS and 'OO pretending to be FP' and other functionally-inspired world we owe to Haskell, but to Javascript we owe the exact opposite, whatever that might be.

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org
12