What is the purpose of relations containing tuples/relations?
Quote from Dave Voorhis on June 18, 2019, 9:20 amQuote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmQuote from AntC on June 17, 2019, 2:11 pm...
And I think to say something in TTM is "isomorphic" to something in OO is just exacerbating the confusion.
Object-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
Quote from dandl on June 18, 2019, 12:15 am[...]
Yes, it is more or less possible to fake value types in an OO language, even in Java. You can use static to create a singleton, implement all the equals and hash code functions and block internal meddling with private, but almost no-one ever does. Most OO programmers explicitly think of terms of little packets of state and the methods used to manipulate that state. They routinely pass object references as arguments to functions knowing that the method will mutate its inputs as well as provide an explicit output. There is a whole discipline about query-command separation.
None of that happens in FP languages and value types. Values are just values, no matter how complex. If you want to mutate state expressed as a complex value, you have to provide some other kind of bundling principle. Yes, you can have a function that takes a value as an argument and produces another value of the same type as its result, but there are a lot of steps between that single function and "accomplishing the same end" with an OO class and a rich set of attached mutators.
I'm not sure how faking value types, what most OO programmers think of, what FP languages do, what values are, etc., is relevant here.
Quote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmQuote from AntC on June 17, 2019, 2:11 pm...
And I think to say something in TTM is "isomorphic" to something in OO is just exacerbating the confusion.
Object-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
Quote from dandl on June 18, 2019, 12:15 am[...]
Yes, it is more or less possible to fake value types in an OO language, even in Java. You can use static to create a singleton, implement all the equals and hash code functions and block internal meddling with private, but almost no-one ever does. Most OO programmers explicitly think of terms of little packets of state and the methods used to manipulate that state. They routinely pass object references as arguments to functions knowing that the method will mutate its inputs as well as provide an explicit output. There is a whole discipline about query-command separation.
None of that happens in FP languages and value types. Values are just values, no matter how complex. If you want to mutate state expressed as a complex value, you have to provide some other kind of bundling principle. Yes, you can have a function that takes a value as an argument and produces another value of the same type as its result, but there are a lot of steps between that single function and "accomplishing the same end" with an OO class and a rich set of attached mutators.
I'm not sure how faking value types, what most OO programmers think of, what FP languages do, what values are, etc., is relevant here.
Quote from dandl on June 18, 2019, 11:27 amQuote from Dave Voorhis on June 18, 2019, 9:20 amQuote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmObject-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
And POINT is precisely the kind of example I do not want to use. I don't recall ever seeing an implementation or use of a POINT type which behaved as a piece of encapsulated state, with its internals being updated by method calls. It's a value type, even if you don't bother with the full fakery I outline elsewhere in this message. We'll need a much better example than that.
I'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
Quote from Dave Voorhis on June 18, 2019, 9:20 amQuote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmObject-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
And POINT is precisely the kind of example I do not want to use. I don't recall ever seeing an implementation or use of a POINT type which behaved as a piece of encapsulated state, with its internals being updated by method calls. It's a value type, even if you don't bother with the full fakery I outline elsewhere in this message. We'll need a much better example than that.
I'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
Quote from johnwcowan on June 18, 2019, 12:29 pmQuote from AntC on June 18, 2019, 2:53 a
Thanks for that reference, but hmm? the wiki says "sometimes cited as the first computer-based functional programming language" is IPL 1956. And perhaps LISP in 1950's (very debatable how much that's FP). PAL was based on Landin's ISWIM design 1966. I see developers include James H Morris (is that of Brooker+Morris compiler-compiler?) and Martin Richards, who developed BCPL = "Basically Christopher's Programming Language" Christopher Strachey of CPL, the CPL that inspired 'Structured Programming' Dahl/Dijkstra/Hoare. Dahl who went on to develop Simula. What a time to be alive in programming languages!
None of these languages are pure (though none the worse for that). I suspect the use of computer-based there reflects the recognition that the lambda calculus itself is pure and functional.
Quote from AntC on June 18, 2019, 2:53 a
Thanks for that reference, but hmm? the wiki says "sometimes cited as the first computer-based functional programming language" is IPL 1956. And perhaps LISP in 1950's (very debatable how much that's FP). PAL was based on Landin's ISWIM design 1966. I see developers include James H Morris (is that of Brooker+Morris compiler-compiler?) and Martin Richards, who developed BCPL = "Basically Christopher's Programming Language" Christopher Strachey of CPL, the CPL that inspired 'Structured Programming' Dahl/Dijkstra/Hoare. Dahl who went on to develop Simula. What a time to be alive in programming languages!
None of these languages are pure (though none the worse for that). I suspect the use of computer-based there reflects the recognition that the lambda calculus itself is pure and functional.
Quote from johnwcowan on June 18, 2019, 1:36 pmQuote from dandl on June 18, 2019, 11:27 amAnd POINT is precisely the kind of example I do not want to use. I don't recall ever seeing an implementation or use of a POINT type which behaved as a piece of encapsulated state, with its internals being updated by method calls.
java.awt.Point (present in Java since 1.0) at your service: mutable points. Since this is meant for points on the screen, its components are integers.
TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
Since the point of computer programs is to mutate the Real World (otherwise they just use up electricity), if they are to have a representation of part of the Real World, either that has to be mutable too, or at least there has to be a variable (analogous to dbvars and relvars) which says which View is the current view. In the first case, creating a new Model can have the side effect of mutating the View singleton to point to itself; in the second case, creating a Model can call the View constructor, passing the current View and itself and then changing the currentView variable.
At least that's the best I can do in 15 minutes. I'm sure it can be improved. In the end, though, all updates are performance hacks except updating the currentWorld with a new World; that's the insight of FRP, which does that operation in an event loop outside the purview of the FRP program.
Quote from dandl on June 18, 2019, 11:27 am
And POINT is precisely the kind of example I do not want to use. I don't recall ever seeing an implementation or use of a POINT type which behaved as a piece of encapsulated state, with its internals being updated by method calls.
java.awt.Point (present in Java since 1.0) at your service: mutable points. Since this is meant for points on the screen, its components are integers.
TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
Since the point of computer programs is to mutate the Real World (otherwise they just use up electricity), if they are to have a representation of part of the Real World, either that has to be mutable too, or at least there has to be a variable (analogous to dbvars and relvars) which says which View is the current view. In the first case, creating a new Model can have the side effect of mutating the View singleton to point to itself; in the second case, creating a Model can call the View constructor, passing the current View and itself and then changing the currentView variable.
At least that's the best I can do in 15 minutes. I'm sure it can be improved. In the end, though, all updates are performance hacks except updating the currentWorld with a new World; that's the insight of FRP, which does that operation in an event loop outside the purview of the FRP program.
Quote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 amQuote from Dave Voorhis on June 18, 2019, 9:20 amQuote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmObject-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
And POINT is precisely the kind of example I do not want to use.
Oh. I thought it was precisely the sort of thing we were talking about here, in terms of notional isomorphisms between TTM multiple possreps and object-oriented multiple constructors (or multiple static factory methods). Indeed, Point is exactly the sort of thing I had in mind, and the sort of thing I thought you and others had in mind when the discussion deviated into talk about value objects and (shall we say, for languages without "true" value objects) "value objects".
My code tends to be fairly full of them, sometimes with multiple constructors in a manner very much resembling what appears to be intended by TTM's multiple possreps.
Quote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
Quote from dandl on June 18, 2019, 11:27 amQuote from Dave Voorhis on June 18, 2019, 9:20 amQuote from dandl on June 18, 2019, 12:15 amQuote from Dave Voorhis on June 17, 2019, 2:29 pmObject-oriented (immutable value) objects + static factory methods (or constructors) are isomorphic to TTM multiple possreps to the extent that I described and no more. I have intentionally not said they're the same thing, because they're not.
However, programming-wise, a given developer implementing a given application in two languages -- a D with multiple possreps, and a conventional object-oriented language -- will almost certainly use multiple possreps or multiple constructors (or static factory methods) equivalently to accomplish the same end.
And this is precisely the point I disagree with. And since I would have thought you know better, I'm interested in why you say this.
I say it because it's a reasonable approach. Let's imagine the desired goal is to implement a mechanism to represent 2D points.
In a typical object-oriented language, you might define a class Point with two factory methods -- to get around the fact that constructors would otherwise collide; Point(double, double) with Point(double, double) -- so Cartesian(double x, double y) for cartesian coordinates and Polar(double r, double theta) for polar coordinates.
In a D with multiple possreps, you might define a type Point with two possreps -- Cartesian(x RATIONAL, y RATIONAL) for cartesian coordinates and Polar(r RATIONAL, theta RATIONAL) for polar coordinates.
Obviously, there are other ways of accomplishing the same end, but this approach -- assuming certain requirements -- would certainly work.
And POINT is precisely the kind of example I do not want to use.
Oh. I thought it was precisely the sort of thing we were talking about here, in terms of notional isomorphisms between TTM multiple possreps and object-oriented multiple constructors (or multiple static factory methods). Indeed, Point is exactly the sort of thing I had in mind, and the sort of thing I thought you and others had in mind when the discussion deviated into talk about value objects and (shall we say, for languages without "true" value objects) "value objects".
My code tends to be fairly full of them, sometimes with multiple constructors in a manner very much resembling what appears to be intended by TTM's multiple possreps.
Quote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
Quote from dandl on June 19, 2019, 1:05 amQuote from johnwcowan on June 18, 2019, 1:36 pmTileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
Since the point of computer programs is to mutate the Real World (otherwise they just use up electricity), if they are to have a representation of part of the Real World, either that has to be mutable too, or at least there has to be a variable (analogous to dbvars and relvars) which says which View is the current view. In the first case, creating a new Model can have the side effect of mutating the View singleton to point to itself; in the second case, creating a Model can call the View constructor, passing the current View and itself and then changing the currentView variable.
No, that won't do. The whole point of Model-View is that the model is ignorant of the view. The View watches the Model and constructs a visible representation as needed.
At least that's the best I can do in 15 minutes. I'm sure it can be improved. In the end, though, all updates are performance hacks except updating the currentWorld with a new World; that's the insight of FRP, which does that operation in an event loop outside the purview of the FRP program.
Most games engines run a game loop. It's not FRP, but can get close. The View runs every frame, but it only has work to do if its Model has changed, which was the result of something else that changed some time previously, which would be user input or physics. or animation or something. But this is not really the point. See my response to Dave.
Quote from johnwcowan on June 18, 2019, 1:36 pmTileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
Since the point of computer programs is to mutate the Real World (otherwise they just use up electricity), if they are to have a representation of part of the Real World, either that has to be mutable too, or at least there has to be a variable (analogous to dbvars and relvars) which says which View is the current view. In the first case, creating a new Model can have the side effect of mutating the View singleton to point to itself; in the second case, creating a Model can call the View constructor, passing the current View and itself and then changing the currentView variable.
No, that won't do. The whole point of Model-View is that the model is ignorant of the view. The View watches the Model and constructs a visible representation as needed.
At least that's the best I can do in 15 minutes. I'm sure it can be improved. In the end, though, all updates are performance hacks except updating the currentWorld with a new World; that's the insight of FRP, which does that operation in an event loop outside the purview of the FRP program.
Most games engines run a game loop. It's not FRP, but can get close. The View runs every frame, but it only has work to do if its Model has changed, which was the result of something else that changed some time previously, which would be user input or physics. or animation or something. But this is not really the point. See my response to Dave.
Quote from dandl on June 19, 2019, 2:16 amQuote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
So now we get to the nub. In OO everything is (more or less) an object. There is a useful division between those that act as pure values, and those that have modifiable state. It is common for objects to hold references to other objects, and there are lots of rules for how to do that (Patterns and Principles). So what changes in TTM, and how different is it?
TTM scalar values are directly analogous to OO value types (struct in C# or C++, by convention in Java). POSSREPs are directly analogous to multiple constructors or factory methods of OO value types. There is no such direct analog with OO mutable classes. There are no POSSREPs, no selectors (of the kind in RM Pre 4).
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
I don't have any reason to think that TTM and its type system would fall short on tackling this problem, but I do still think that the structure of the program would be greatly different. Using TTM types and relvars and doing set-oriented updates is a lot different from the OO way.
Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
Quote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
So now we get to the nub. In OO everything is (more or less) an object. There is a useful division between those that act as pure values, and those that have modifiable state. It is common for objects to hold references to other objects, and there are lots of rules for how to do that (Patterns and Principles). So what changes in TTM, and how different is it?
TTM scalar values are directly analogous to OO value types (struct in C# or C++, by convention in Java). POSSREPs are directly analogous to multiple constructors or factory methods of OO value types. There is no such direct analog with OO mutable classes. There are no POSSREPs, no selectors (of the kind in RM Pre 4).
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
I don't have any reason to think that TTM and its type system would fall short on tackling this problem, but I do still think that the structure of the program would be greatly different. Using TTM types and relvars and doing set-oriented updates is a lot different from the OO way.
Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
Quote from AntC on June 19, 2019, 7:30 amQuote from dandl on June 19, 2019, 2:16 amQuote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 am
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
Em, I know nothing about writing gaming software. I know nothing about using gaming software. I have no idea why the unwashed youth want to pore over screens getting RSI and weakening their eyesight. But I can respond to some of the qs.
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
So an industrial D would have a type synonym declaration: this name is a shorthand for the full relvar heading. Something like a macro. You bang on calling this a problem repeatedly. What's so hard?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
What does a
Grid
contain other than collections of bits and pieces? Is there only oneGrid
in the database? Is it just 'the database'? Do "not forget that relations with [cardinality one] are respectable and interesting," -- to misquote RM Pro 5. I see nothing hard here.
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
Put a constraint on the relvar to say it must be a singleton. For example give it a key with no components. "D shall not forget that relations ..., nor that candidate keys with no components are likewise respectable and interesting." (RM Pro 5 again) I see nothing hard here.
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
TileView
has data content that represents what's currently displayed on the screen.TileModel
has data content that's been changed by whatever. You can compare two relvars or relation values in a D (RM Pre 8), you perhaps need to run a query over them to get to the same type/format; if they're different, update the view. ... or ...
TileView
has a timestamp for when you last painted the screen;TileModel
has a timestamp for when last changed. I see nothing hard here.
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
Is the variable holding a value that makes sense to the user, and could be displayed to them? Then it's 'business data' and not a pointer (nor a surrogate). Is it an
ObjectId
because every object in OOP needs one of those? Then yes it's a pointer in the sense of OO Pro 2 (and/or RM Pro 2). Don't do that. Find a key that makes sense to the user. Quite possibly it'll be compound. Then you'll need to hold it in a tuplevar. I see nothing hard here.Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
I don't see relational types as so different from collection types in most languages -- granted pre 1980's languages didn't have collection types (other than arrays), you had to build them with pointers and ugly stuff. Yes relational types are different to scalars -- that's why they're called "non-scalars". I guess many languages that support collection types require you process them RowByAgonisingRow, rather than "set-oriented updates". Is that hard conceptually?
Quote from dandl on June 19, 2019, 2:16 amQuote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 am
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
Em, I know nothing about writing gaming software. I know nothing about using gaming software. I have no idea why the unwashed youth want to pore over screens getting RSI and weakening their eyesight. But I can respond to some of the qs.
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
So an industrial D would have a type synonym declaration: this name is a shorthand for the full relvar heading. Something like a macro. You bang on calling this a problem repeatedly. What's so hard?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
What does a Grid
contain other than collections of bits and pieces? Is there only one Grid
in the database? Is it just 'the database'? Do "not forget that relations with [cardinality one] are respectable and interesting," -- to misquote RM Pro 5. I see nothing hard here.
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
Put a constraint on the relvar to say it must be a singleton. For example give it a key with no components. "D shall not forget that relations ..., nor that candidate keys with no components are likewise respectable and interesting." (RM Pro 5 again) I see nothing hard here.
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
TileView
has data content that represents what's currently displayed on the screen. TileModel
has data content that's been changed by whatever. You can compare two relvars or relation values in a D (RM Pre 8), you perhaps need to run a query over them to get to the same type/format; if they're different, update the view. ... or ...
TileView
has a timestamp for when you last painted the screen; TileModel
has a timestamp for when last changed. I see nothing hard here.
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
Is the variable holding a value that makes sense to the user, and could be displayed to them? Then it's 'business data' and not a pointer (nor a surrogate). Is it an ObjectId
because every object in OOP needs one of those? Then yes it's a pointer in the sense of OO Pro 2 (and/or RM Pro 2). Don't do that. Find a key that makes sense to the user. Quite possibly it'll be compound. Then you'll need to hold it in a tuplevar. I see nothing hard here.
Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
I don't see relational types as so different from collection types in most languages -- granted pre 1980's languages didn't have collection types (other than arrays), you had to build them with pointers and ugly stuff. Yes relational types are different to scalars -- that's why they're called "non-scalars". I guess many languages that support collection types require you process them RowByAgonisingRow, rather than "set-oriented updates". Is that hard conceptually?
Quote from Dave Voorhis on June 19, 2019, 9:23 amQuote from dandl on June 19, 2019, 2:16 amQuote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
So now we get to the nub. In OO everything is (more or less) an object. There is a useful division between those that act as pure values, and those that have modifiable state. It is common for objects to hold references to other objects, and there are lots of rules for how to do that (Patterns and Principles). So what changes in TTM, and how different is it?
TTM scalar values are directly analogous to OO value types (struct in C# or C++, by convention in Java). POSSREPs are directly analogous to multiple constructors or factory methods of OO value types. There is no such direct analog with OO mutable classes. There are no POSSREPs, no selectors (of the kind in RM Pre 4).
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
I don't have any reason to think that TTM and its type system would fall short on tackling this problem, but I do still think that the structure of the program would be greatly different. Using TTM types and relvars and doing set-oriented updates is a lot different from the OO way.
Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
The topic has drifted, so I'm going to restart this in a new thread... I've moved it to here.
Quote from dandl on June 19, 2019, 2:16 amQuote from Dave Voorhis on June 18, 2019, 8:43 pmQuote from dandl on June 18, 2019, 11:27 amI'm currently writing a game based on a hex grid, with tiles and loops. I have Point, Rect, Hex, Layout, Orientation, Piece and Arc as value types, but Tile, Grid, Board, Game and most of the others are implemented as mutable classes. Take TileModel for example, which provides the data to be consumed by TileView and displayed on the screen. TileModel has a property method called IsChanged which will be true if the model has changed since it was last displayed, meaning that the view needs to be updated. TileView keeps a reference to TileModel which it can query as needed. It's a familiar OO pattern.
So given that my purpose is to implement a model and a view on that model in the way set out here, how would you express that in the TTM type system? I think I might be able to find a way, but I can't see that the approach would have much in common with the OO way I've described here.
In the TTM world, Point, Rect, Hex, Layout, Orientation, Piece and Arc would be types. Tile, Grid, Board, Game and (probably) most of the others would be relvars.
Mutable (and perhaps persistent) state is best represented by relvars (of relations containing tuples) which contain values; values are defined by types.
So now we get to the nub. In OO everything is (more or less) an object. There is a useful division between those that act as pure values, and those that have modifiable state. It is common for objects to hold references to other objects, and there are lots of rules for how to do that (Patterns and Principles). So what changes in TTM, and how different is it?
TTM scalar values are directly analogous to OO value types (struct in C# or C++, by convention in Java). POSSREPs are directly analogous to multiple constructors or factory methods of OO value types. There is no such direct analog with OO mutable classes. There are no POSSREPs, no selectors (of the kind in RM Pre 4).
Your proposition is that variables of a relational type (relvars) are the only holders of mutable state, and are therefore to be considered as replacements for class objects (instances). Using my example above, how would you deal with the following?
- We have no POSSREPs, so do we write a whole bunch of factory methods instead?
- Relational types have a name comprising the entire heading, but my OO classes are called Grid and Board. Surely we don't want to write that full name as the type of every operator that manipulates a Grid or Board? Do we need a language extension to allow for user-defined relation type names?
- Relvars deal naturally with collections, such as a set of Tiles, but my Grid is a singleton, which has 6 properties including a list of tiles and a list of loops on those tiles. How does this work?
- If most relvars have to be singletons, how do we ensure this is so (and what happens if it isn't)??
- My TileView holds a reference to a TileModel and during update asks the model: did you change? So how does the TTM equivalent do that?
- If a scalar variable is used to hold a key, and that key is used to look up a row in a relation, isn't that just a pointer by another name?
I don't have any reason to think that TTM and its type system would fall short on tackling this problem, but I do still think that the structure of the program would be greatly different. Using TTM types and relvars and doing set-oriented updates is a lot different from the OO way.
Having written this, I started wondering whether part of the problem is the peculiar syntax of Tutorial D, which makes relational types so different from scalars in how they appear and are used in the language. Maybe if relation and tuple types had ordinary user-defined names and functions (including selectors) had named arguments instead of positional, a simpler and more uniform syntax would help. But that's a topic for another time.
The topic has drifted, so I'm going to restart this in a new thread... I've moved it to here.