Life after J
Quote from Dave Voorhis on April 12, 2021, 9:19 amQuote from dandl on April 11, 2021, 11:29 pmQuote from Dave Voorhis on April 11, 2021, 3:46 pmQuote from dandl on April 11, 2021, 2:47 pmI'm afraid you've lost me here. It's not clear what point you're trying to make.
The point is simple enough. Rather than adding more detail, more complexity, more features to the GP languages we have:
- Make languages that are safer by removing lower level concerns such nulls, exceptions, casts and so on (which the compiler can deal with)
- Then make them higher by removing implementation detail such as bits, bytes, characters and in due course strings, tuples, arrays
- With the aim of making them shorter, so that less code does more work.
These are things many people have tried to do, and always got stuck because the things that got left out turned out to be needed and the X chunk couldn't talk to the Y chunk. But I do see the time getting closer. We're so used to our close-to-the-metal programming paradigm we think it has to be that way, but now when I write C++ I now realise how truly terrible it is to have to stoop so low. I credit Linq and Andl for seeing hints of how it might be.
I'm still entirely baffled by where you're going with all this, but...
LINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
Quote from dandl on April 11, 2021, 11:29 pmQuote from Dave Voorhis on April 11, 2021, 3:46 pmQuote from dandl on April 11, 2021, 2:47 pmI'm afraid you've lost me here. It's not clear what point you're trying to make.
The point is simple enough. Rather than adding more detail, more complexity, more features to the GP languages we have:
- Make languages that are safer by removing lower level concerns such nulls, exceptions, casts and so on (which the compiler can deal with)
- Then make them higher by removing implementation detail such as bits, bytes, characters and in due course strings, tuples, arrays
- With the aim of making them shorter, so that less code does more work.
These are things many people have tried to do, and always got stuck because the things that got left out turned out to be needed and the X chunk couldn't talk to the Y chunk. But I do see the time getting closer. We're so used to our close-to-the-metal programming paradigm we think it has to be that way, but now when I write C++ I now realise how truly terrible it is to have to stoop so low. I credit Linq and Andl for seeing hints of how it might be.
I'm still entirely baffled by where you're going with all this, but...
LINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
Quote from dandl on April 12, 2021, 10:44 amLINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Then you totally miss my point. As long as those features remain in the language and you have to make a case by case decision whether to use them or not, your code is not safe; and you cannot lift your thinking higher until you can totally ignore those low level concerns. I respect those who can deal with the complexity and make those choices, but I don't respect their decision to remain stuck at that level.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
As of SE8, 2014. LINQ was released in .NET 3.5, back in 2007.
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
As above, you completely miss my point. As long as the decision remains, about whether you 'need' low level operations, your thought processes are tied to that level. You may enjoy shooting alligators, but you won't be draining any swamps.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
And your emphasis for that sweeping statement? Not that it matters -- I just reviewed one of my C# projects and (apart from a few test programs) I can't find any imperative code. What I do find is mutable state spread out over multiple objects, and that's more the kind of problem that FP addresses.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
There is nothing intrinsically wrong with the idea of 'do this, do that, do a bit more, now we're done'. The problem is how to raise the level of the chunks beyond what the abstraction capabilities of our languages currently allow. In my view relations are one small part of safer and higher. I might come up with another 10 or 20 comparable higher level data structures and algorithms, each depending on its own peculiar semantics, and run into the same tired objections. I need the compiler's help to make them safe or I can't move higher.
LINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Then you totally miss my point. As long as those features remain in the language and you have to make a case by case decision whether to use them or not, your code is not safe; and you cannot lift your thinking higher until you can totally ignore those low level concerns. I respect those who can deal with the complexity and make those choices, but I don't respect their decision to remain stuck at that level.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
As of SE8, 2014. LINQ was released in .NET 3.5, back in 2007.
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
As above, you completely miss my point. As long as the decision remains, about whether you 'need' low level operations, your thought processes are tied to that level. You may enjoy shooting alligators, but you won't be draining any swamps.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
And your emphasis for that sweeping statement? Not that it matters -- I just reviewed one of my C# projects and (apart from a few test programs) I can't find any imperative code. What I do find is mutable state spread out over multiple objects, and that's more the kind of problem that FP addresses.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
There is nothing intrinsically wrong with the idea of 'do this, do that, do a bit more, now we're done'. The problem is how to raise the level of the chunks beyond what the abstraction capabilities of our languages currently allow. In my view relations are one small part of safer and higher. I might come up with another 10 or 20 comparable higher level data structures and algorithms, each depending on its own peculiar semantics, and run into the same tired objections. I need the compiler's help to make them safe or I can't move higher.
Quote from Dave Voorhis on April 12, 2021, 11:12 amQuote from dandl on April 12, 2021, 10:44 amLINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Then you totally miss my point. As long as those features remain in the language and you have to make a case by case decision whether to use them or not, your code is not safe; and you cannot lift your thinking higher until you can totally ignore those low level concerns. I respect those who can deal with the complexity and make those choices, but I don't respect their decision to remain stuck at that level.
I am indeed missing your point. I've been trying to get it, but I don't get it.
I am not making a case by case decision whether to use certain features or not. I build low level mechanisms that use low level functionality and compose them to create higher level mechanisms. Then I use the higher level mechanisms which do not require low level mechanisms.
There are, to a certain extent, high level mechanisms that can't avoid certain low-level semantics in (say) Java -- like references and their null pointer exceptions -- but that's inherent in Java semantics. Safety of those can be improved by using, say, Kotlin.
But this is all at a 3GL level. We really need to move above the 3GL level, and I've seen this done well in at least one case. It currently means giving up almost all of the facilities of 3GL languages, though, or at least isolating them into "safe" regions of caged unsafety.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
As of SE8, 2014. LINQ was released in .NET 3.5, back in 2007.
Indeed. So the current Java development world has lambdas and streams. Even the most "legacy" active Java project I know of is using Java 8 with lambdas and streams.
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
As above, you completely miss my point. As long as the decision remains, about whether you 'need' low level operations, your thought processes are tied to that level. You may enjoy shooting alligators, but you won't be draining any swamps.
I don't think about whether I 'need' low level operations. I use low level operations to compose higher level operations, and the higher level operations don't need low level operations.
But, again, that's all 3GL-level work. You need to look to pure functional and logical languages to genuinely achieve higher levels of abstraction.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
And your emphasis for that sweeping statement? Not that it matters -- I just reviewed one of my C# projects and (apart from a few test programs) I can't find any imperative code. What I do find is mutable state spread out over multiple objects, and that's more the kind of problem that FP addresses.
You can't find any imperative code?
If it's C#, it's entirely imperative code with expressions. C# isn't functional at all. It has some functional-inspired facilities (like LINQ), but is still entirely imperative.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
There is nothing intrinsically wrong with the idea of 'do this, do that, do a bit more, now we're done'. The problem is how to raise the level of the chunks beyond what the abstraction capabilities of our languages currently allow. In my view relations are one small part of safer and higher. I might come up with another 10 or 20 comparable higher level data structures and algorithms, each depending on its own peculiar semantics, and run into the same tired objections. I need the compiler's help to make them safe or I can't move higher.
Ordering is imperative.
Relations are merely one form of container; relational algebra is a set of operations on that kind of container. They are no safer or higher than any other container mechanism or encapsulated-and-abstracted-as-classes-and-instances machinery. In that respect, they are no different from strings, arrays, matrices, LINQ, and Java Streams.
I again suggest looking at Prolog and Datalog. These genuinely redefine programming as a higher level abstraction, and they're safer.
Quote from dandl on April 12, 2021, 10:44 amLINQ is a halfway implementation of functional programming, limited to certain mechanisms, constrained by the limitations of an otherwise imperative language. To really see how far the notion can (and perhaps should) be taken, look at Haskell, ML, F#, Lisp, and (in a different direction) Prolog.
No, I already knew all that stuff and used all those languages. What Linq showed me was the direct reduction in code complexity and ability to think at a higher level within a language that was otherwise unchanged. [In the same way my recent trip back into C++ showed me all the horrible gritty detail that Java/C# already omitted.] In other respects C# is problematic: Linq required several additions to the language, so the overall cognitive load is higher, and that's also my experience with Haskell, Lisp and Prolog. The languages are complex and powerful, and still involve dealing with a lot of low level concerns.
They support dealing with a lot of low level concerns, but do not obligate them.
Used well, the low level concerns only appear at a low level. That's good programming, and good abstraction.
Used poorly, low level concerns are propagated at every level. That's bad programming.
Then you totally miss my point. As long as those features remain in the language and you have to make a case by case decision whether to use them or not, your code is not safe; and you cannot lift your thinking higher until you can totally ignore those low level concerns. I respect those who can deal with the complexity and make those choices, but I don't respect their decision to remain stuck at that level.
I am indeed missing your point. I've been trying to get it, but I don't get it.
I am not making a case by case decision whether to use certain features or not. I build low level mechanisms that use low level functionality and compose them to create higher level mechanisms. Then I use the higher level mechanisms which do not require low level mechanisms.
There are, to a certain extent, high level mechanisms that can't avoid certain low-level semantics in (say) Java -- like references and their null pointer exceptions -- but that's inherent in Java semantics. Safety of those can be improved by using, say, Kotlin.
But this is all at a 3GL level. We really need to move above the 3GL level, and I've seen this done well in at least one case. It currently means giving up almost all of the facilities of 3GL languages, though, or at least isolating them into "safe" regions of caged unsafety.
Re safer, removing nulls is good, though somewhat complicated by conventional programming languages that embed null in the fundamental language semantics. The rest are -- or should be -- only at the closest-to-the-metal layer and abstracted away above it. I can't remember the last time I used a cast at an application level in Java, and exceptions should be for things that are truly exceptional -- like the network or disk drive goes away -- to allow controlled exit or shutdown, not how they're sometimes used as a (bad) way to return additional values from a method call.
Your higher and shorter appear to be your personal discovery of abstraction and procedures. It seems unlikely that you've only just discovered these, but perhaps your understanding of their application and meaning is new?
I'm not seeing that so far, though. I haven't seen anything to suggest anything but conventional interpretations of abstraction and procedures.
I won't argue with your personal experience with Java. Mine is different, but you know where the dragons are and how to avoid them. What I'm proposing is most certainly abstraction, but procedures are not enough. You can't add streams to Java without first adding lambdas, you have to change the core of the language. You can't add TTM relations to Java just by writing a few procedures, the compiler won't check headings for you. And you can't even properly think about higher until after safer frees you from the grunge. Which I think is where you are now: up to your armpits in Java grunge.
You're aware that Java has lambdas and streams, yes?
As of SE8, 2014. LINQ was released in .NET 3.5, back in 2007.
Indeed. So the current Java development world has lambdas and streams. Even the most "legacy" active Java project I know of is using Java 8 with lambdas and streams.
Again, Java supports relatively low level operations for when you need them and sometimes you do, but doesn't obligate them when you don't. In many ways, Java hits a sweet spot of eliding aspects of C++ that are unnecessary for the majority of application development whilst avoiding needless cruft, which is undoubtedly a reason for its sustained popularity even against arguably "better" languages like C#. It's not ideal in terms of safety, but compatible languages like Kotlin and Scala are stronger in that respect so there's a migration path if that's the direction you want to take.
As above, you completely miss my point. As long as the decision remains, about whether you 'need' low level operations, your thought processes are tied to that level. You may enjoy shooting alligators, but you won't be draining any swamps.
I don't think about whether I 'need' low level operations. I use low level operations to compose higher level operations, and the higher level operations don't need low level operations.
But, again, that's all 3GL-level work. You need to look to pure functional and logical languages to genuinely achieve higher levels of abstraction.
In short, Java and its safer derivatives are adequate for most 3GL application programming. Their real limitation is that they're imperative.
And your emphasis for that sweeping statement? Not that it matters -- I just reviewed one of my C# projects and (apart from a few test programs) I can't find any imperative code. What I do find is mutable state spread out over multiple objects, and that's more the kind of problem that FP addresses.
You can't find any imperative code?
If it's C#, it's entirely imperative code with expressions. C# isn't functional at all. It has some functional-inspired facilities (like LINQ), but is still entirely imperative.
As for being unable to faithfully implement TTM semantics without compromises, that is perhaps unfortunate, though I don't doubt it would be possible to create a Java-like (or Kotlin-like, or whatever) language that implements TTM semantics. But it almost certainly wouldn't be much different in terms of overall power. You'd replace Java Streams with TTM relations and relational operators, which would perhaps suit our intuition better, but in terms of overall expressivity it would be essentially the same.
Again, the real limitation is that we'd simply be trading one imperative 3GL for another.
There is nothing intrinsically wrong with the idea of 'do this, do that, do a bit more, now we're done'. The problem is how to raise the level of the chunks beyond what the abstraction capabilities of our languages currently allow. In my view relations are one small part of safer and higher. I might come up with another 10 or 20 comparable higher level data structures and algorithms, each depending on its own peculiar semantics, and run into the same tired objections. I need the compiler's help to make them safe or I can't move higher.
Ordering is imperative.
Relations are merely one form of container; relational algebra is a set of operations on that kind of container. They are no safer or higher than any other container mechanism or encapsulated-and-abstracted-as-classes-and-instances machinery. In that respect, they are no different from strings, arrays, matrices, LINQ, and Java Streams.
I again suggest looking at Prolog and Datalog. These genuinely redefine programming as a higher level abstraction, and they're safer.