The Forum for Discussion about The Third Manifesto and Related Matters

You need to log in to create posts and topics.

Types and all that @*#$.

12
Quote from Dave Voorhis on November 6, 2019, 10:30 pm

If an object's type changes as a result of mutation, then the object is a variable. Indeed, a mutable object is a variable (or set of variables) whether its type changes or not.

I think of an object as a fixed-size collection of variables and/or values: in TTM the only object is the database.  Relvars are not "pure" variables either, because they have properties associated with them other than a name and a value.

It's true that you can always push mutability up to the next meta level, saying that the database doesn't change, it's just that a unique database variable gets a new value, and so on until there is only one variable, WORLD, all of whose values are completely immutable, so that when I stand up or think a new thought, haven't changed, it's just that JOHN_COWAN is now holding a new value that in principle can be unrelated to the old value, except that both of them must satisfy whatever constraints that variable may be associated with.  As Quine said, to be is to be the value of a (quantified) variable.  But as Dennett said in another connection, when talking of persons this is a dire and counterintuitive route indeed.

In any case, the only reason I have been talking about objects at all is that we live in an age of object-oriented languages, not in an age of value-oriented languages, except D and Haskell and some others.

In statically typed languages with inheritance, an expression evaluates to a value whose type is the expression's type, but is assignable to a variable of the supertype because the type is the supertype. Because inheritance...

If the type were the supertype, they would have the same elements.  Cf. the TTM book, online p. 57:  "a type is a set of values (more precisely, a named set of values), but it would be more correct to say it is the set of all values that satisfy a certain type constraint."  Rather, every element of the type is an element of the supertype.

But you knew that.

In dynamically-typed languages, an expression evaluates to a value of the type it denotes, and that value can be assigned to any variable.

Here is a Python function:

def plus(a, b):
    return a + b

What type does the expression a + b denote?  The type ALPHA (though Python calls it Any), and that is the type of every expression in Python (modulo type inference).

My point in intentionally quibbling here is to highlight the fact that as long as we speak informally, loosely and vaguely, there will be innumerable informal, loose, and vague interpretations.

Unfortunately, formality and obscurity can go together (and often do, in my experience).

Quote from johnwcowan on November 6, 2019, 11:08 pm

 

In any case, the only reason I have been talking about objects at all is that we live in an age of object-oriented languages, not in an age of value-oriented languages, except D and Haskell and some others.

And COBOL and Fortran and ALGOL60/Pascal and CPL and therefore BCPL and therefore C; and assembly languages. And McCarthy's LISP and Iverson's APL ...

You live in an age of object-oriented languages, maybe. I grew up in an age of procedural/modular languages; then became an implementor/educator/project manager of systems written in I-don't-care-what-language/paradigm. Then came back to programming because lambda calculus and Damas-Hindley-Milner.

So I've always worked and programmed under value semantics, and mostly static typing. I've taken hints from Dave on this forum that the 'best practice' for using OOP is also value semantics and static typing and not bundling methods with data. And therefore not having to worry about subtyping and inheritance and pointer semantics amongst classes/instances/objects. I think history might find that some 'features' of object-oriented languages turn out to be aberrations, and future programmers will wonder: how on earth did anybody program with all that unnecessary complexity? To which the answer will be: badly.

It seems to me that value semantics is exactly what we want for the database and queries extracted from it. Then why pollute a data manipulation language with some other semantic/typing model?

From the interminable debates here on both TTM's IM and OOP's inheritance (which seems to be not-so-subtly dependent on which language we're talking about) I've reached exactly one conclusion: inheritance in both those senses is a nest of vipers, and I want nothing of it.

I did post a few days ago on the 'how else to express squares are rectangles?' thread a different take/language proposal on expressing X are Y. You might or might not want to call it inheritance. The approach has been used successfully for managing on-screen 'objects'/properties for GUIs, so is not just applicable for squares are rectangles or Managers are Employees.

Quote from AntC on November 7, 2019, 2:30 am

I've taken hints from Dave on this forum that the 'best practice' for using OOP is also value semantics and static typing and not bundling methods with data. And therefore not having to worry about subtyping and inheritance and pointer semantics amongst classes/instances/objects. I think history might find that some 'features' of object-oriented languages turn out to be aberrations, and future programmers will wonder: how on earth did anybody program with all that unnecessary complexity? To which the answer will be: badly.

To expand on this, since I've been invoked...

The bundling of methods with data is essentially unavoidable in the popular object-oriented programming languages. You can (sort of) avoid it in, say, Java and C#, but the result is much, much worse. In Java and C#, you're better to bundle methods with the data they manipulate.

Though such bundling is not a core principle or best practice despite sometimes being unavoidable. (Those of you inclined to cry, "but encapsulation! ENCAPSULATION!" when this point is made -- shush, you.) Unbundling methods from data -- and providing multiple dispatch, which unbundling permits and encourages -- would be better, but popular languages do what they do. You can write very readable, maintainable code that bundles methods with data.

Avoiding stateful programming and dynamic typing in favour of value semantics and static typing is best practice in all programming, not just object oriented programming. Unfortunately, weak teaching plus disinterest in code quality tends to encourage willy-nilly state and mutability and run-time checking. Bad programs result.

Inheritance and polymorphism-via-inheritance are dangerous cutting tools. When used appropriately, they're fine. They can even be elegant, and complementary to generics/templates, interfaces, and other substitutability mechanisms.

But they are all dangerous cutting tools. Overuse of any dangerous cutting tool presents risk of harm, but not using cutting tools when they're appropriate is just as harmful in a different way. Balancing competing risks in a readable -- and safe -- way is a mark of good programming, no matter what the language. Unfortunately, most programmers are bad programmers all the time, and the relatively few good programmers are bad programmers some of the time, so bad code occurs in every language. I don't blame the language features -- at least, not in the usual statically-typed popular programming languages -- I blame their misuse and overuse. Used properly, appropriately and judiciously (and thus rarely), they're fine.

Would languages that prevent such misuse be better?

Probably, but I have no doubt that bad programmers -- and good programmers being bad -- would find ways to misuse their features just as often in new and equally horrible ways.

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 Dave Voorhis on November 7, 2019, 11:12 am
Quote from AntC on November 7, 2019, 2:30 am

I've taken hints from Dave on this forum that the 'best practice' for using OOP is also value semantics and static typing and not bundling methods with data. And therefore not having to worry about subtyping and inheritance and pointer semantics amongst classes/instances/objects. I think history might find that some 'features' of object-oriented languages turn out to be aberrations, and future programmers will wonder: how on earth did anybody program with all that unnecessary complexity? To which the answer will be: badly.

To expand on this, since I've been invoked...

The bundling of methods with data is essentially unavoidable in the popular object-oriented programming languages. You can (sort of) avoid it in, say, Java and C#, but the result is much, much worse. In Java and C#, you're better to bundle methods with the data they manipulate.

Though such bundling is not a core principle or best practice despite sometimes being unavoidable. (Those of you inclined to cry, "but encapsulation! ENCAPSULATION!" when this point is made -- shush, you.) Unbundling methods from data -- and providing multiple dispatch, which unbundling permits and encourages -- would be better, but popular languages do what they do. You can write very readable, maintainable code that bundles methods with data.

Avoiding stateful programming and dynamic typing in favour of value semantics and static typing is best practice in all programming, not just object oriented programming. Unfortunately, weak teaching plus disinterest in code quality tends to encourage willy-nilly state and mutability and run-time checking. Bad programs result.

Inheritance and polymorphism-via-inheritance are dangerous cutting tools. When used appropriately, they're fine. They can even be elegant, and complementary to generics/templates, interfaces, and other substitutability mechanisms.

But they are all dangerous cutting tools. Overuse of any dangerous cutting tool presents risk of harm, but not using cutting tools when they're appropriate is just as harmful in a different way. Balancing competing risks in a readable -- and safe -- way is a mark of good programming, no matter what the language. Unfortunately, most programmers are bad programmers all the time, and the relatively few good programmers are bad programmers some of the time, so bad code occurs in every language. I don't blame the language features -- at least, not in the usual statically-typed popular programming languages -- I blame their misuse and overuse. Used properly, appropriately and judiciously (and thus rarely), they're fine.

Would languages that prevent such misuse be better?

Probably, but I have no doubt that bad programmers -- and good programmers being bad -- would find ways to misuse their features just as often in new and equally horrible ways.

I agree with most of this, but I would place greater emphasis on scope/namespace/visibility/encapsulation than just state on its own. I can deal with just about any kind of language in 100 lines of code, the challenge is size and the associated complexity. If the rules allow something over here to affect something thousands of lines of code away over there, it's going to bite you sooner or later. Encapsulation is not enough, if 'public' is the easy option. The language cannot prevent horrible code, but it can certainly make it easier or harder to ring fence bits that might otherwise become dependencies. OO makes it really easy to do certain kinds of encapsulation, and harder to do others. I assume an industrial D would do something clever in that department, but I can only guess what that might be.

Andl - A New Database Language - andl.org
Quote from AntC on November 7, 2019, 2:30 am

And COBOL and Fortran and ALGOL60/Pascal and CPL and therefore BCPL and therefore C; and assembly languages. And McCarthy's LISP and Iverson's APL ...

While I see what you mean, all of those are heavily dependent on mutable data structures (arrays, if nothing else, which often aren't even first-class) with the exception of the very earliest Lisp 1.0.

You live in an age of object-oriented languages, maybe.

I mean that in the same sense that I live in the age of Facebook and right-wing pseudo-populist governments: I don't use the one and I didn't vote for the others, but there they are, bestriding this world like colossi.

I grew up in an age of procedural/modular languages

Likewise.

It seems to me that value semantics is exactly what we want for the database and queries extracted from it. Then why pollute a data manipulation language with some other semantic/typing model?

I agree entirely.  Relvars contain relation values, or there are no relvars and the dbvar contains named relation values, as you will.

From the interminable debates here on both TTM's IM and OOP's inheritance (which seems to be not-so-subtly dependent on which language we're talking about) I've reached exactly one conclusion: inheritance in both those senses is a nest of vipers, and I want nothing of it.

It is.  I have an alternative to existing non-flat type systems that I call Celebes Kalossi, which I'll talk about in due course.  It eliminates inheritance in favor of two orthogonal concepts: subtyping and incorporation.

Quote from johnwcowan on November 7, 2019, 10:59 pm
Quote from AntC on November 7, 2019, 2:30 am

 

It seems to me that value semantics is exactly what we want for the database and queries extracted from it. Then why pollute a data manipulation language with some other semantic/typing model?

I agree entirely.  Relvars contain relation values, or there are no relvars and the dbvar contains named relation values, as you will.

From the interminable debates here on both TTM's IM and OOP's inheritance (which seems to be not-so-subtly dependent on which language we're talking about) I've reached exactly one conclusion: inheritance in both those senses is a nest of vipers, and I want nothing of it.

It is.  I have an alternative to existing non-flat type systems that I call Celebes Kalossi, which I'll talk about in due course.  It eliminates inheritance in favor of two orthogonal concepts: subtyping and incorporation.

"Surabaya Johnny. Is it really the end?" [to be sung in that so-atmospheric Lotte Lenya ironic voice]

Quote from johnwcowan on November 7, 2019, 10:59 pm
Quote from AntC on November 7, 2019, 2:30 am

And COBOL and Fortran and ALGOL60/Pascal and CPL and therefore BCPL and therefore C; and assembly languages. And McCarthy's LISP and Iverson's APL ...

 

You live in an age of object-oriented languages, maybe.

I mean that in the same sense that I live in the age of Facebook and right-wing pseudo-populist governments: I don't use the one and I didn't vote for the others, but there they are, bestriding this world like colossi.

Nonsense: despite the huge numbers of Facebook users, that's well less than half the population (and note the users 'churn': not every account is a distinct person; not every account is active); pseudo-"populist" governments never get as much as half the popular vote. (The Nazi party got just over 30%; Margaret Thatcher not much more.) They're not representative of the age. They're representative of dysfunctional electoral systems in countries without proportional representation/with bizarre Electoral College systems and sclerotic double-chambers. (The two Dakotas have as many Senators each as the whole of California: an economy large enough to be the world's fourth on its own!) No such colossi.

Turning to programming languages: I think you'll find COBOL/Fortran still more heavily used than OOP -- in the sense of lines-of-code executed per day, as opposed to lines-of-code written and maintained. That's because Java is verbose compared to COBOL and especially compared to Fortran, and needing more nursing and feeding than a COBOL application. And I should of course have mentioned another language with value semantics: SQL. (Presuming the Object-Oriented features of it are not actually used anywhere.)

I grew up in an age of procedural/modular languages

Likewise.

It seems to me that value semantics is exactly what we want for the database and queries extracted from it. Then why pollute a data manipulation language with some other semantic/typing model?

I agree entirely.  Relvars contain relation values, or there are no relvars and the dbvar contains named relation values, as you will.

I've moved your earlier point:

While I see what you mean, all of those [procedural languages] are heavily dependent on mutable data structures (arrays, if nothing else, which often aren't even first-class) with the exception of the very earliest Lisp 1.0.

Much as I dislike mutable data structures, I think that's the mental abstraction we need in a multi-user database context. Previous debate on the forum has claimed that single-user databases are valid so the semantics of a D should treat the dbvar/relvars as variables within the program. I say: such a small use case it's not worth considering.

The dbvar is a mutable data structure outside the program. No program can assume that from one END COMMIT; to its next START COMMIT; the database has persisted as was. The semantics of querying and update must be that quite possibly some other user has done DROP TABLE *; or at least DELETE * FROM *. We can perhaps presume the schema has not changed behind our backs, but that militates against mixing DML with DDL in the same language.

Then a D must be structured such that all (mutable) state is held in the database. Holding state purely within the program/inside objects is a recipe for anomalies. I guess I allow state to also reside on the users' screens -- which the program should treat as another external data structure.

A program's access to the database must always be between START COMMIT; ...; END COMMIT; blocks even for queries, and should be expressed as a mapping from current state (content unknown) to to-be state. So I've always chafed against RM Pre 21's holus bolus assignment operator := wrt updating the database.

wrt your "[not] even first-class", I'm not seeing why that's wrong or relevant: the dbvar/relvars are typed; that limits what operations can apply. From your first post:

 Relvars are not "pure" variables either, because they have properties associated with them other than a name and a value.

They have a type (or rather the data structures they denote do). Is that what you mean by "properties"? Under TTM they have a heading. That's the type. Other properties like keys or FunctionalDependencies we can also express as (phantom) type. Inter-relvar constraints are properties of the whole dbvar, strictly speaking, then can be expressed as (phantom) type.

Quote from AntC on November 8, 2019, 6:37 am

That's because Java is verbose compared to COBOL and especially compared to Fortran, and needing more nursing and feeding than a COBOL application.

Poor Java, always suffering under decade-old misconceptions.

For years, it was "Java is too slow", when it was only too slow for a year after its release due to lack of JIT compilation. We finally dispensed with that one only to get "Java is too verbose", when modern Java is blessed with:

  • Type inference, so no more awkwardly repetitious "Type variable = new Type()" or "Type1<Type2> variable = new Type1<Type2>()";
  • Lambdas, so no more clunky inner classes; and
  • Streams, so expressions instead of stateful loops and record-by-agonising-record processing.

The JVM is no longer distributed separately from applications -- applications now bundle a JVM -- so nursing and feeding requirements are no different from any other application.

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 AntC on November 8, 2019, 6:37 am

 Relvars are not "pure" variables either, because they have properties associated with them other than a name and a value.

They have a type (or rather the data structures they denote do). Is that what you mean by "properties"? Under TTM they have a heading. That's the type. Other properties like keys or FunctionalDependencies we can also express as (phantom) type. Inter-relvar constraints are properties of the whole dbvar, strictly speaking, then can be expressed as (phantom) type.

Per TTM relvars have properties such as virtual; base/real; application; private.

Andl - A New Database Language - andl.org
Quote from AntC on November 8, 2019, 6:37 am

Much as I dislike mutable data structures, I think that's the mental abstraction we need in a multi-user database context. Previous debate on the forum has claimed that single-user databases are valid so the semantics of a D should treat the dbvar/relvars as variables within the program. I say: such a small use case it's not worth considering.

The dbvar is a mutable data structure outside the program. No program can assume that from one END COMMIT; to its next START COMMIT; the database has persisted as was. The semantics of querying and update must be that quite possibly some other user has done DROP TABLE *; or at least DELETE * FROM *. We can perhaps presume the schema has not changed behind our backs, but that militates against mixing DML with DDL in the same language.

Then a D must be structured such that all (mutable) state is held in the database. Holding state purely within the program/inside objects is a recipe for anomalies. I guess I allow state to also reside on the users' screens -- which the program should treat as another external data structure.

A program's access to the database must always be between START COMMIT; ...; END COMMIT; blocks even for queries, and should be expressed as a mapping from current state (content unknown) to to-be state. So I've always chafed against RM Pre 21's holus bolus assignment operator := wrt updating the database.

I think you may be conflating the conceptual framework (TTM) and tutorial-oriented illustration of the conceptual framework (Tutorial D) with an as-yet-undescribed Industrial D. That Industrial D would unquestionably provide appropriate multiuser and transaction-handling facilities, but what those might look like is outside the scope of TTM.

 

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