Life after D
Quote from dandl on March 17, 2021, 11:06 pmQuote from Dave Voorhis on March 17, 2021, 2:57 pmQuote from dandl on March 17, 2021, 1:32 pmThe premise is shorter-safer-higher. Nobody wants to write 1000 lines of HTML when 100 lines of something else will do the same job, with less room for errors.
Those who do HTML-first (if I may call it that) do it with 0 lines of code using Balsamiq or Axure or equivalent, or they prefer to write 1000 lines of HTML/CSS. Either way, it's to achieve an intended look-and-feel.
Of course. I'm only railing against authored HTML. HTML as a file interchange format is just fine. Just don't make me read it or write it.
Really?
These days, there's two ways I do a Web interface: Either bang it out in raw HTML/CSS (+JS if needed), or I don't touch HTML/CSS/JS at all and use my Spoing framework or raw RAP/RWT in Java.
Either are far superior to either yet another inadequate interface definition language, or (ugh) some dire interface painter (though I don't deprecate those who use them and love them), because I can quickly create simple interfaces or implement monstrously complex interaction. The Java solution is far easier for complex interactivity, though.
So how many years of practice does it take to do that? Now tell me how long it takes before a competent programmer can acquire those skills. And do you still hold the same view if the language/tools allow that period to be shortened from years to hours?
If it's acceptable for the look-and-feel to be constrained to some subset of HTML/CSS capability, then that's fine -- until you need some portion of HTML/CSS capability that your tool didn't provide.
The problem here is that the pervasiveness of HTML/CSS simultaneously defines broad expectations in control over style, and narrowly enforces an annoying lack of capability (e.g., specify a set of three cascading or otherwise interdependent drop-down comboboxes, where -- in addition -- the selections in two of the comboboxes are partially filtered by the contents of a textbox if a checkbox is ticked, etc.) that can only be reasonably overcome with browser-side JavaScript (which may have to communicate dynamically with the server-side.)
It's not good, but it's almost unavoidable.
I don't know anyone doing anything but JS these days. Why do you think NPM is so big, and JS is near the top of the language list?
And that's another bad language in serious need of a makeover (just one, not dozens of them). But that's another story, not my bag.
I don't know anyone doing JS in the core enterprise space, except for some lightweight instrumentation of Docker containers and the like. They usually use Typescript, though, which is a few thousand percent better than raw JS.
I don't know any that aren't. I just checked a local bank: https://www.anz.com.au/personal/. They have 9 JS includes on the home page (including react) and the entire site uses JS throughout. What planet were you talking about? What's not 'core enterprise' about a bank?
Yes, many use languages that transpile into JS, of which Typescript is particularly popular in the MS space, but many don't.
There's a huge hobbyist and small Website JS following, though I do sometimes see it -- outside of core instrumentation -- in peripheral, usually throwaway, we-need-it-for-the-two-week-campaign-then-delete-it type Node projects. It's good for that.
Per the TIOBE Index, C, Java, Python, C++ and C# are the top five (in order), with JavaScript ranked seventh after Visual Basic. That's near the top, but look what languages are at the top...
Typescript is #41, which is a bit unfortunate, but I'm sure it will grow.
JS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Quote from Dave Voorhis on March 17, 2021, 2:57 pmQuote from dandl on March 17, 2021, 1:32 pmThe premise is shorter-safer-higher. Nobody wants to write 1000 lines of HTML when 100 lines of something else will do the same job, with less room for errors.
Those who do HTML-first (if I may call it that) do it with 0 lines of code using Balsamiq or Axure or equivalent, or they prefer to write 1000 lines of HTML/CSS. Either way, it's to achieve an intended look-and-feel.
Of course. I'm only railing against authored HTML. HTML as a file interchange format is just fine. Just don't make me read it or write it.
Really?
These days, there's two ways I do a Web interface: Either bang it out in raw HTML/CSS (+JS if needed), or I don't touch HTML/CSS/JS at all and use my Spoing framework or raw RAP/RWT in Java.
Either are far superior to either yet another inadequate interface definition language, or (ugh) some dire interface painter (though I don't deprecate those who use them and love them), because I can quickly create simple interfaces or implement monstrously complex interaction. The Java solution is far easier for complex interactivity, though.
So how many years of practice does it take to do that? Now tell me how long it takes before a competent programmer can acquire those skills. And do you still hold the same view if the language/tools allow that period to be shortened from years to hours?
If it's acceptable for the look-and-feel to be constrained to some subset of HTML/CSS capability, then that's fine -- until you need some portion of HTML/CSS capability that your tool didn't provide.
The problem here is that the pervasiveness of HTML/CSS simultaneously defines broad expectations in control over style, and narrowly enforces an annoying lack of capability (e.g., specify a set of three cascading or otherwise interdependent drop-down comboboxes, where -- in addition -- the selections in two of the comboboxes are partially filtered by the contents of a textbox if a checkbox is ticked, etc.) that can only be reasonably overcome with browser-side JavaScript (which may have to communicate dynamically with the server-side.)
It's not good, but it's almost unavoidable.
I don't know anyone doing anything but JS these days. Why do you think NPM is so big, and JS is near the top of the language list?
And that's another bad language in serious need of a makeover (just one, not dozens of them). But that's another story, not my bag.
I don't know anyone doing JS in the core enterprise space, except for some lightweight instrumentation of Docker containers and the like. They usually use Typescript, though, which is a few thousand percent better than raw JS.
I don't know any that aren't. I just checked a local bank: https://www.anz.com.au/personal/. They have 9 JS includes on the home page (including react) and the entire site uses JS throughout. What planet were you talking about? What's not 'core enterprise' about a bank?
Yes, many use languages that transpile into JS, of which Typescript is particularly popular in the MS space, but many don't.
There's a huge hobbyist and small Website JS following, though I do sometimes see it -- outside of core instrumentation -- in peripheral, usually throwaway, we-need-it-for-the-two-week-campaign-then-delete-it type Node projects. It's good for that.
Per the TIOBE Index, C, Java, Python, C++ and C# are the top five (in order), with JavaScript ranked seventh after Visual Basic. That's near the top, but look what languages are at the top...
Typescript is #41, which is a bit unfortunate, but I'm sure it will grow.
JS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Quote from dandl on March 17, 2021, 11:27 pmWise words, but you still fail to capture that distinction between tool maker and tool user.
I don't consider it to be a significant distinction, except at rather narrow extremes -- with the laboriously-write-a-simple-script non-programmer at one end and the full-time compiler developer at the other. In between is everybody else, where all programmers are a mix of tool developers and tool users.
I already knew that: it's obvious in all you write. Doesn't mean you're right.
Indeed, a friend of mine who would be the last to describe himself as a programmer delights in telling tales of an early job he had writing SAS code to write SAS code, because (as a non-programmer) he found writing SAS code to solve problems too dull and tedious, so he wrote SAS programs to generate SAS programs to solve problems.
Was he a tool user?
Or a tool developer?
I don't know, and I'm not sure it matters. A good language should support both. An excellent language should encourage both using just the language.
It matters. And no, they're different. Everyone who writes code for other programmers to use is a tool maker. Everyone who does not is not. Some people do both, but most do not.
Yes, every major app builds up a library of routines in whatever form is available (modules, functions, classes, whatever), and many apps can be written by stringing together calls to those routines in the host language. Please note: the developer and maintainer of those routines takes on the role of tool maker; tool users just use what they're given (and complain when it doesn't work right). This is key.
Python seems part way along that path. I always thought its object orientation was a stumbling block to achieving it, because its OO support is ungainly, half-baked and awkward. It turns out that most non-professional Python programmers never define their own classes, so that's an issue that doesn't come up. But for the beginner/non-professional who becomes proficient enough to want to use classes, they are there.
I imagine the new language we're talking about being the same, but ideally without the flaws: There can be features that the beginner/non-professional might never use, but they are there in case they're wanted. The language should thus support a continuous spectrum of developers -- from rank beginner non-programmers at one end to fully-capable professionals at the other -- with none of the discontinuous breaks in assumed developer ability (or target language) that are inevitably be created by defining a 4GL with "escapes" to (a) 3GL(s).
For context, here is 'hello world':
Java:
class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } }
C:#include <stdio.h> int main() { printf("Hello World!"); return 0; } Powerflex: WRITELN "Hello World!"In each case we have a 5 to one reduction in code lines, at least that in places for bugs and a focus on what is to be done, not comiler cruft. Shorter-safer-higher.
That's an example usually used to illustrate how C and Java (or C#, just change some capitalisation) are verbose (and therefore wrong) whilst Python or Ruby or JavaScript or <insert language here> are so right.
Of course, they don't mention that:
- The Java/C#-ish example embodies the Java/C# philosophy of everything-in-a-class, so main (or Main) is defined in a class, and any or multiple classes can be program entry points in a given project; or
- The C example is helpfully explicit about the header file that defines 'printf' (and it's not strictly required in this case), and it clearly shows that main() is a function that returns a value, which is very useful when integrating C programs with shell/Python/whatever scripts to invoke them; or
- The (usually Python or Ruby or JavaScript) Powerflex code doesn't indicate the entry point at all, so fundamental semantic information is missing; or
- A typical developer might never specify a main (or Main) entry point in their entire careers, either because they use a framework that defines it internally or they never start a project from scratch.
That said, I appreciate the value of clarity and I'm not sure the C or Java/C#-ish examples are particularly clear, and there are no doubt better ways of specifying "this is the (or a) entry point."
But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
What I'm on about is separating tool building from tool use: making it way easier to create, maintain and extend the LYN. APL is a super example of the LYN for writing certain kinds of mathematical expressions, hampered by some awkward choices of symbols. We should be able to create a 'New APL' easily to replace it, but we can't.
This is mostly an aside, but there is a 'New APL'. It's called J, designed and implemented in part by the same Ken Iverson who invented APL.
From jsoftware.com: "J is a high-level, general-purpose programming language that is particularly suited to the mathematical, statistical, and logical analysis of data. [...] Jd ( J database) is a high-performance columnar RDBMS written in J that is geared toward storing and analyzing large amounts of data. Jd is free for non-commercial use. Jd lives openly and dynamically in the J execution and development environment, so that the full power of J is available to the application developer. For example, Jd columns are mapped to J nouns, so built-in J primitives can apply directly to the data."
Sounds like it might be just what you're looking for.
Yes, I know about J. It's on my list of languages I need to try. But it's not on the meta-programming path.
Ditto for 4GLs, like dBase and Powerflex.
I don't know about Powerflex or Dataflex (which I understand it resembles?) but in the 1980's I created some utilities (in assembly language -- they were Terminate-and-Stay-Resident utilities, back when those were a thing) for a consultant who used Dataflex.
I think that highlights one of the limitations of such languages, which is that its developers inevitably want functionality that they'd like to have been able to create within the language, but couldn't.
(Well, maybe not TSR utilities, as those were a special category of hack, but the principle is good -- the language should be capable, within reason, of doing whatever a developer might want even if the average developer can't.)
Yes, Powerflex is historically compatible with Dataflex, but diverged from it long ago. A skilled programmer can write just about any application program, including Window API access and forms, Web client and server, Unix portable, SQL hosted and queries, COM objects, mountains of stuff. And very substantial meta-programming, via type-sensitive macros with compile-time arithmetic. I had a lot of fun building it, but I don't like programming in it, for all the usual reasons.
It sounds like it has the right semantics. Why not change the syntax so it's more appealing?
Isn't that just a 'new' 4GL by another name?
Maybe, but I'm not convinced that "maps readily unto the underlying 3GL" is anywhere near as good as "3GL with zero accidental complexity, that can fully express the things that need to be done for business purpose via syntactically-friendly libraries, is maintainable and extensible as needed, and achieves what the user likes."
I don't see the distinction, but you did give yourself a challenge: how will you fulfil these aims other than by the kind of language MP extension outlined above?
"What the user likes" is a (maybe the) key ingredient, and it isn't necessarily shorter, safer (sigh -- I have many debates with proponents of dynamic typing), or higher. It might include (or be) other qualities -- like fun to use -- that are much more persuasive in getting users to switch from whatever they use now.
The user likes to get the job done, without pain or undue effort. Other than resisting change, I don't see anyone arguing against shorter-safer-higher. The question is how.
The user likes what's fun. Observation of hundreds of business users over the years tells me that whilst pain and undue effort negatively affect tool appeal, merely being painless and effortless is not enough to make a tool appealing.
It needs to be fun.
Something quite notable about Python is the degree to which beginner or otherwise non-professional programmers will spend endless hours attempting to get buggy Python code working, and enjoy it.
There's a similar enjoyment I've observed in Excel users. They may be, at best, marginally productive, but as long as they're having fun, it's good.
My thesis is that writing less code with less bugs and getting more useful output in less time is just as much fun. So I'll make a proposal as a separate post.
Wise words, but you still fail to capture that distinction between tool maker and tool user.
I don't consider it to be a significant distinction, except at rather narrow extremes -- with the laboriously-write-a-simple-script non-programmer at one end and the full-time compiler developer at the other. In between is everybody else, where all programmers are a mix of tool developers and tool users.
I already knew that: it's obvious in all you write. Doesn't mean you're right.
Indeed, a friend of mine who would be the last to describe himself as a programmer delights in telling tales of an early job he had writing SAS code to write SAS code, because (as a non-programmer) he found writing SAS code to solve problems too dull and tedious, so he wrote SAS programs to generate SAS programs to solve problems.
Was he a tool user?
Or a tool developer?
I don't know, and I'm not sure it matters. A good language should support both. An excellent language should encourage both using just the language.
It matters. And no, they're different. Everyone who writes code for other programmers to use is a tool maker. Everyone who does not is not. Some people do both, but most do not.
Yes, every major app builds up a library of routines in whatever form is available (modules, functions, classes, whatever), and many apps can be written by stringing together calls to those routines in the host language. Please note: the developer and maintainer of those routines takes on the role of tool maker; tool users just use what they're given (and complain when it doesn't work right). This is key.
Python seems part way along that path. I always thought its object orientation was a stumbling block to achieving it, because its OO support is ungainly, half-baked and awkward. It turns out that most non-professional Python programmers never define their own classes, so that's an issue that doesn't come up. But for the beginner/non-professional who becomes proficient enough to want to use classes, they are there.
I imagine the new language we're talking about being the same, but ideally without the flaws: There can be features that the beginner/non-professional might never use, but they are there in case they're wanted. The language should thus support a continuous spectrum of developers -- from rank beginner non-programmers at one end to fully-capable professionals at the other -- with none of the discontinuous breaks in assumed developer ability (or target language) that are inevitably be created by defining a 4GL with "escapes" to (a) 3GL(s).
For context, here is 'hello world':
Java:
class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } }
C:#include <stdio.h> int main() { printf("Hello World!"); return 0; } Powerflex: WRITELN "Hello World!"In each case we have a 5 to one reduction in code lines, at least that in places for bugs and a focus on what is to be done, not comiler cruft. Shorter-safer-higher.
That's an example usually used to illustrate how C and Java (or C#, just change some capitalisation) are verbose (and therefore wrong) whilst Python or Ruby or JavaScript or <insert language here> are so right.
Of course, they don't mention that:
- The Java/C#-ish example embodies the Java/C# philosophy of everything-in-a-class, so main (or Main) is defined in a class, and any or multiple classes can be program entry points in a given project; or
- The C example is helpfully explicit about the header file that defines 'printf' (and it's not strictly required in this case), and it clearly shows that main() is a function that returns a value, which is very useful when integrating C programs with shell/Python/whatever scripts to invoke them; or
- The (usually Python or Ruby or JavaScript) Powerflex code doesn't indicate the entry point at all, so fundamental semantic information is missing; or
- A typical developer might never specify a main (or Main) entry point in their entire careers, either because they use a framework that defines it internally or they never start a project from scratch.
That said, I appreciate the value of clarity and I'm not sure the C or Java/C#-ish examples are particularly clear, and there are no doubt better ways of specifying "this is the (or a) entry point."
But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) {
println("Hello, World!")
}
Still too much cruft.
What I'm on about is separating tool building from tool use: making it way easier to create, maintain and extend the LYN. APL is a super example of the LYN for writing certain kinds of mathematical expressions, hampered by some awkward choices of symbols. We should be able to create a 'New APL' easily to replace it, but we can't.
This is mostly an aside, but there is a 'New APL'. It's called J, designed and implemented in part by the same Ken Iverson who invented APL.
From jsoftware.com: "J is a high-level, general-purpose programming language that is particularly suited to the mathematical, statistical, and logical analysis of data. [...] Jd ( J database) is a high-performance columnar RDBMS written in J that is geared toward storing and analyzing large amounts of data. Jd is free for non-commercial use. Jd lives openly and dynamically in the J execution and development environment, so that the full power of J is available to the application developer. For example, Jd columns are mapped to J nouns, so built-in J primitives can apply directly to the data."
Sounds like it might be just what you're looking for.
Yes, I know about J. It's on my list of languages I need to try. But it's not on the meta-programming path.
Ditto for 4GLs, like dBase and Powerflex.
I don't know about Powerflex or Dataflex (which I understand it resembles?) but in the 1980's I created some utilities (in assembly language -- they were Terminate-and-Stay-Resident utilities, back when those were a thing) for a consultant who used Dataflex.
I think that highlights one of the limitations of such languages, which is that its developers inevitably want functionality that they'd like to have been able to create within the language, but couldn't.
(Well, maybe not TSR utilities, as those were a special category of hack, but the principle is good -- the language should be capable, within reason, of doing whatever a developer might want even if the average developer can't.)
Yes, Powerflex is historically compatible with Dataflex, but diverged from it long ago. A skilled programmer can write just about any application program, including Window API access and forms, Web client and server, Unix portable, SQL hosted and queries, COM objects, mountains of stuff. And very substantial meta-programming, via type-sensitive macros with compile-time arithmetic. I had a lot of fun building it, but I don't like programming in it, for all the usual reasons.
It sounds like it has the right semantics. Why not change the syntax so it's more appealing?
Isn't that just a 'new' 4GL by another name?
Maybe, but I'm not convinced that "maps readily unto the underlying 3GL" is anywhere near as good as "3GL with zero accidental complexity, that can fully express the things that need to be done for business purpose via syntactically-friendly libraries, is maintainable and extensible as needed, and achieves what the user likes."
I don't see the distinction, but you did give yourself a challenge: how will you fulfil these aims other than by the kind of language MP extension outlined above?
"What the user likes" is a (maybe the) key ingredient, and it isn't necessarily shorter, safer (sigh -- I have many debates with proponents of dynamic typing), or higher. It might include (or be) other qualities -- like fun to use -- that are much more persuasive in getting users to switch from whatever they use now.
The user likes to get the job done, without pain or undue effort. Other than resisting change, I don't see anyone arguing against shorter-safer-higher. The question is how.
The user likes what's fun. Observation of hundreds of business users over the years tells me that whilst pain and undue effort negatively affect tool appeal, merely being painless and effortless is not enough to make a tool appealing.
It needs to be fun.
Something quite notable about Python is the degree to which beginner or otherwise non-professional programmers will spend endless hours attempting to get buggy Python code working, and enjoy it.
There's a similar enjoyment I've observed in Excel users. They may be, at best, marginally productive, but as long as they're having fun, it's good.
My thesis is that writing less code with less bugs and getting more useful output in less time is just as much fun. So I'll make a proposal as a separate post.
Quote from Dave Voorhis on March 17, 2021, 11:44 pmQuote from dandl on March 17, 2021, 11:06 pmQuote from Dave Voorhis on March 17, 2021, 2:57 pmQuote from dandl on March 17, 2021, 1:32 pmThe premise is shorter-safer-higher. Nobody wants to write 1000 lines of HTML when 100 lines of something else will do the same job, with less room for errors.
Those who do HTML-first (if I may call it that) do it with 0 lines of code using Balsamiq or Axure or equivalent, or they prefer to write 1000 lines of HTML/CSS. Either way, it's to achieve an intended look-and-feel.
Of course. I'm only railing against authored HTML. HTML as a file interchange format is just fine. Just don't make me read it or write it.
Really?
These days, there's two ways I do a Web interface: Either bang it out in raw HTML/CSS (+JS if needed), or I don't touch HTML/CSS/JS at all and use my Spoing framework or raw RAP/RWT in Java.
Either are far superior to either yet another inadequate interface definition language, or (ugh) some dire interface painter (though I don't deprecate those who use them and love them), because I can quickly create simple interfaces or implement monstrously complex interaction. The Java solution is far easier for complex interactivity, though.
So how many years of practice does it take to do that? Now tell me how long it takes before a competent programmer can acquire those skills. And do you still hold the same view if the language/tools allow that period to be shortened from years to hours?
If tools could replace years of UI/UX design and related programming ability with a few hours of work for non-professional developers, we'd all be out of work.
The reality is that replace-all-the-code -- whether for some part of programming (like UIs) or all of it -- has been promised since the late 1950's (arguably, COBOL was the first attempt) and we're still no closer to it happening except in limited, narrow niches.
...And to a certain extent, except for Excel and other spreadsheet programs, of course, but those require considerable time and skills development to become capable, too.
Development tools and development capability represent a spectrum, with ease and limited capability on the low/no-code side to the left; complexity and arbitrary capability of full-stack programming on the right. That's true for every aspect of programming, not just UIs.
The problem is that an individual starting out on some point on that spectrum sooner or later wants to move further to the right without giving up the tool. No/Low/Simplified-code systems run out of capability at an arbitrary point on the spectrum, either providing no route to more capability, or ramping up to difficulty more arduous than a general-purpose tool.
The solution is better general-purpose programming languages, not emasculated special-purpose "programming" languages, and being able to leverage technologies and facilities that are popular. As I've suggested before, the language needs to provide a continuum of usable capability; ease for the beginner on the left, power for the programmer on the right, but a completely seamless journey along that spectrum. That includes being able to use existing application development approaches, like providing services to predefined HTML/CSS/JS front-ends.
If it's acceptable for the look-and-feel to be constrained to some subset of HTML/CSS capability, then that's fine -- until you need some portion of HTML/CSS capability that your tool didn't provide.
The problem here is that the pervasiveness of HTML/CSS simultaneously defines broad expectations in control over style, and narrowly enforces an annoying lack of capability (e.g., specify a set of three cascading or otherwise interdependent drop-down comboboxes, where -- in addition -- the selections in two of the comboboxes are partially filtered by the contents of a textbox if a checkbox is ticked, etc.) that can only be reasonably overcome with browser-side JavaScript (which may have to communicate dynamically with the server-side.)
It's not good, but it's almost unavoidable.
I don't know anyone doing anything but JS these days. Why do you think NPM is so big, and JS is near the top of the language list?
And that's another bad language in serious need of a makeover (just one, not dozens of them). But that's another story, not my bag.
I don't know anyone doing JS in the core enterprise space, except for some lightweight instrumentation of Docker containers and the like. They usually use Typescript, though, which is a few thousand percent better than raw JS.
I don't know any that aren't. I just checked a local bank: https://www.anz.com.au/personal/. They have 9 JS includes on the home page (including react) and the entire site uses JS throughout. What planet were you talking about? What's not 'core enterprise' about a bank?
That's not core. That's a website front-end. Edge stuff, an endpoint.
Core is backend. It's business logic, databases, data processing, financial trading, accounting, stats and reporting. All the stuff in and behind the RESTful interface to the Website front-end. Banking is mostly back-end.
Yes, many use languages that transpile into JS, of which Typescript is particularly popular in the MS space, but many don't.
There's a huge hobbyist and small Website JS following, though I do sometimes see it -- outside of core instrumentation -- in peripheral, usually throwaway, we-need-it-for-the-two-week-campaign-then-delete-it type Node projects. It's good for that.
Per the TIOBE Index, C, Java, Python, C++ and C# are the top five (in order), with JavaScript ranked seventh after Visual Basic. That's near the top, but look what languages are at the top...
Typescript is #41, which is a bit unfortunate, but I'm sure it will grow.
JS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Quote from dandl on March 17, 2021, 11:06 pmQuote from Dave Voorhis on March 17, 2021, 2:57 pmQuote from dandl on March 17, 2021, 1:32 pmThe premise is shorter-safer-higher. Nobody wants to write 1000 lines of HTML when 100 lines of something else will do the same job, with less room for errors.
Those who do HTML-first (if I may call it that) do it with 0 lines of code using Balsamiq or Axure or equivalent, or they prefer to write 1000 lines of HTML/CSS. Either way, it's to achieve an intended look-and-feel.
Of course. I'm only railing against authored HTML. HTML as a file interchange format is just fine. Just don't make me read it or write it.
Really?
These days, there's two ways I do a Web interface: Either bang it out in raw HTML/CSS (+JS if needed), or I don't touch HTML/CSS/JS at all and use my Spoing framework or raw RAP/RWT in Java.
Either are far superior to either yet another inadequate interface definition language, or (ugh) some dire interface painter (though I don't deprecate those who use them and love them), because I can quickly create simple interfaces or implement monstrously complex interaction. The Java solution is far easier for complex interactivity, though.
So how many years of practice does it take to do that? Now tell me how long it takes before a competent programmer can acquire those skills. And do you still hold the same view if the language/tools allow that period to be shortened from years to hours?
If tools could replace years of UI/UX design and related programming ability with a few hours of work for non-professional developers, we'd all be out of work.
The reality is that replace-all-the-code -- whether for some part of programming (like UIs) or all of it -- has been promised since the late 1950's (arguably, COBOL was the first attempt) and we're still no closer to it happening except in limited, narrow niches.
...And to a certain extent, except for Excel and other spreadsheet programs, of course, but those require considerable time and skills development to become capable, too.
Development tools and development capability represent a spectrum, with ease and limited capability on the low/no-code side to the left; complexity and arbitrary capability of full-stack programming on the right. That's true for every aspect of programming, not just UIs.
The problem is that an individual starting out on some point on that spectrum sooner or later wants to move further to the right without giving up the tool. No/Low/Simplified-code systems run out of capability at an arbitrary point on the spectrum, either providing no route to more capability, or ramping up to difficulty more arduous than a general-purpose tool.
The solution is better general-purpose programming languages, not emasculated special-purpose "programming" languages, and being able to leverage technologies and facilities that are popular. As I've suggested before, the language needs to provide a continuum of usable capability; ease for the beginner on the left, power for the programmer on the right, but a completely seamless journey along that spectrum. That includes being able to use existing application development approaches, like providing services to predefined HTML/CSS/JS front-ends.
If it's acceptable for the look-and-feel to be constrained to some subset of HTML/CSS capability, then that's fine -- until you need some portion of HTML/CSS capability that your tool didn't provide.
The problem here is that the pervasiveness of HTML/CSS simultaneously defines broad expectations in control over style, and narrowly enforces an annoying lack of capability (e.g., specify a set of three cascading or otherwise interdependent drop-down comboboxes, where -- in addition -- the selections in two of the comboboxes are partially filtered by the contents of a textbox if a checkbox is ticked, etc.) that can only be reasonably overcome with browser-side JavaScript (which may have to communicate dynamically with the server-side.)
It's not good, but it's almost unavoidable.
I don't know anyone doing anything but JS these days. Why do you think NPM is so big, and JS is near the top of the language list?
And that's another bad language in serious need of a makeover (just one, not dozens of them). But that's another story, not my bag.
I don't know anyone doing JS in the core enterprise space, except for some lightweight instrumentation of Docker containers and the like. They usually use Typescript, though, which is a few thousand percent better than raw JS.
I don't know any that aren't. I just checked a local bank: https://www.anz.com.au/personal/. They have 9 JS includes on the home page (including react) and the entire site uses JS throughout. What planet were you talking about? What's not 'core enterprise' about a bank?
That's not core. That's a website front-end. Edge stuff, an endpoint.
Core is backend. It's business logic, databases, data processing, financial trading, accounting, stats and reporting. All the stuff in and behind the RESTful interface to the Website front-end. Banking is mostly back-end.
Yes, many use languages that transpile into JS, of which Typescript is particularly popular in the MS space, but many don't.
There's a huge hobbyist and small Website JS following, though I do sometimes see it -- outside of core instrumentation -- in peripheral, usually throwaway, we-need-it-for-the-two-week-campaign-then-delete-it type Node projects. It's good for that.
Per the TIOBE Index, C, Java, Python, C++ and C# are the top five (in order), with JavaScript ranked seventh after Visual Basic. That's near the top, but look what languages are at the top...
Typescript is #41, which is a bit unfortunate, but I'm sure it will grow.
JS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Quote from Dave Voorhis on March 18, 2021, 12:01 amQuote from dandl on March 17, 2021, 11:27 pmWise words, but you still fail to capture that distinction between tool maker and tool user.
I don't consider it to be a significant distinction, except at rather narrow extremes -- with the laboriously-write-a-simple-script non-programmer at one end and the full-time compiler developer at the other. In between is everybody else, where all programmers are a mix of tool developers and tool users.
I already knew that: it's obvious in all you write. Doesn't mean you're right.
Possibly, but I'm often right.
Indeed, a friend of mine who would be the last to describe himself as a programmer delights in telling tales of an early job he had writing SAS code to write SAS code, because (as a non-programmer) he found writing SAS code to solve problems too dull and tedious, so he wrote SAS programs to generate SAS programs to solve problems.
Was he a tool user?
Or a tool developer?
I don't know, and I'm not sure it matters. A good language should support both. An excellent language should encourage both using just the language.
It matters. And no, they're different. Everyone who writes code for other programmers to use is a tool maker. Everyone who does not is not. Some people do both, but most do not.
Again, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Yes, every major app builds up a library of routines in whatever form is available (modules, functions, classes, whatever), and many apps can be written by stringing together calls to those routines in the host language. Please note: the developer and maintainer of those routines takes on the role of tool maker; tool users just use what they're given (and complain when it doesn't work right). This is key.
Python seems part way along that path. I always thought its object orientation was a stumbling block to achieving it, because its OO support is ungainly, half-baked and awkward. It turns out that most non-professional Python programmers never define their own classes, so that's an issue that doesn't come up. But for the beginner/non-professional who becomes proficient enough to want to use classes, they are there.
I imagine the new language we're talking about being the same, but ideally without the flaws: There can be features that the beginner/non-professional might never use, but they are there in case they're wanted. The language should thus support a continuous spectrum of developers -- from rank beginner non-programmers at one end to fully-capable professionals at the other -- with none of the discontinuous breaks in assumed developer ability (or target language) that are inevitably be created by defining a 4GL with "escapes" to (a) 3GL(s).
For context, here is 'hello world':
Java:
class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } }
C:#include <stdio.h> int main() { printf("Hello World!"); return 0; } Powerflex: WRITELN "Hello World!"In each case we have a 5 to one reduction in code lines, at least that in places for bugs and a focus on what is to be done, not comiler cruft. Shorter-safer-higher.
That's an example usually used to illustrate how C and Java (or C#, just change some capitalisation) are verbose (and therefore wrong) whilst Python or Ruby or JavaScript or <insert language here> are so right.
Of course, they don't mention that:
- The Java/C#-ish example embodies the Java/C# philosophy of everything-in-a-class, so main (or Main) is defined in a class, and any or multiple classes can be program entry points in a given project; or
- The C example is helpfully explicit about the header file that defines 'printf' (and it's not strictly required in this case), and it clearly shows that main() is a function that returns a value, which is very useful when integrating C programs with shell/Python/whatever scripts to invoke them; or
- The (usually Python or Ruby or JavaScript) Powerflex code doesn't indicate the entry point at all, so fundamental semantic information is missing; or
- A typical developer might never specify a main (or Main) entry point in their entire careers, either because they use a framework that defines it internally or they never start a project from scratch.
That said, I appreciate the value of clarity and I'm not sure the C or Java/C#-ish examples are particularly clear, and there are no doubt better ways of specifying "this is the (or a) entry point."
But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
What I'm on about is separating tool building from tool use: making it way easier to create, maintain and extend the LYN. APL is a super example of the LYN for writing certain kinds of mathematical expressions, hampered by some awkward choices of symbols. We should be able to create a 'New APL' easily to replace it, but we can't.
This is mostly an aside, but there is a 'New APL'. It's called J, designed and implemented in part by the same Ken Iverson who invented APL.
From jsoftware.com: "J is a high-level, general-purpose programming language that is particularly suited to the mathematical, statistical, and logical analysis of data. [...] Jd ( J database) is a high-performance columnar RDBMS written in J that is geared toward storing and analyzing large amounts of data. Jd is free for non-commercial use. Jd lives openly and dynamically in the J execution and development environment, so that the full power of J is available to the application developer. For example, Jd columns are mapped to J nouns, so built-in J primitives can apply directly to the data."
Sounds like it might be just what you're looking for.
Yes, I know about J. It's on my list of languages I need to try. But it's not on the meta-programming path.
Ditto for 4GLs, like dBase and Powerflex.
I don't know about Powerflex or Dataflex (which I understand it resembles?) but in the 1980's I created some utilities (in assembly language -- they were Terminate-and-Stay-Resident utilities, back when those were a thing) for a consultant who used Dataflex.
I think that highlights one of the limitations of such languages, which is that its developers inevitably want functionality that they'd like to have been able to create within the language, but couldn't.
(Well, maybe not TSR utilities, as those were a special category of hack, but the principle is good -- the language should be capable, within reason, of doing whatever a developer might want even if the average developer can't.)
Yes, Powerflex is historically compatible with Dataflex, but diverged from it long ago. A skilled programmer can write just about any application program, including Window API access and forms, Web client and server, Unix portable, SQL hosted and queries, COM objects, mountains of stuff. And very substantial meta-programming, via type-sensitive macros with compile-time arithmetic. I had a lot of fun building it, but I don't like programming in it, for all the usual reasons.
It sounds like it has the right semantics. Why not change the syntax so it's more appealing?
Isn't that just a 'new' 4GL by another name?
Maybe, but I'm not convinced that "maps readily unto the underlying 3GL" is anywhere near as good as "3GL with zero accidental complexity, that can fully express the things that need to be done for business purpose via syntactically-friendly libraries, is maintainable and extensible as needed, and achieves what the user likes."
I don't see the distinction, but you did give yourself a challenge: how will you fulfil these aims other than by the kind of language MP extension outlined above?
"What the user likes" is a (maybe the) key ingredient, and it isn't necessarily shorter, safer (sigh -- I have many debates with proponents of dynamic typing), or higher. It might include (or be) other qualities -- like fun to use -- that are much more persuasive in getting users to switch from whatever they use now.
The user likes to get the job done, without pain or undue effort. Other than resisting change, I don't see anyone arguing against shorter-safer-higher. The question is how.
The user likes what's fun. Observation of hundreds of business users over the years tells me that whilst pain and undue effort negatively affect tool appeal, merely being painless and effortless is not enough to make a tool appealing.
It needs to be fun.
Something quite notable about Python is the degree to which beginner or otherwise non-professional programmers will spend endless hours attempting to get buggy Python code working, and enjoy it.
There's a similar enjoyment I've observed in Excel users. They may be, at best, marginally productive, but as long as they're having fun, it's good.
My thesis is that writing less code with less bugs and getting more useful output in less time is just as much fun. So I'll make a proposal as a separate post.
I think fun is quite a bit more than that.
Quote from dandl on March 17, 2021, 11:27 pmWise words, but you still fail to capture that distinction between tool maker and tool user.
I don't consider it to be a significant distinction, except at rather narrow extremes -- with the laboriously-write-a-simple-script non-programmer at one end and the full-time compiler developer at the other. In between is everybody else, where all programmers are a mix of tool developers and tool users.
I already knew that: it's obvious in all you write. Doesn't mean you're right.
Possibly, but I'm often right.
Indeed, a friend of mine who would be the last to describe himself as a programmer delights in telling tales of an early job he had writing SAS code to write SAS code, because (as a non-programmer) he found writing SAS code to solve problems too dull and tedious, so he wrote SAS programs to generate SAS programs to solve problems.
Was he a tool user?
Or a tool developer?
I don't know, and I'm not sure it matters. A good language should support both. An excellent language should encourage both using just the language.
It matters. And no, they're different. Everyone who writes code for other programmers to use is a tool maker. Everyone who does not is not. Some people do both, but most do not.
Again, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Yes, every major app builds up a library of routines in whatever form is available (modules, functions, classes, whatever), and many apps can be written by stringing together calls to those routines in the host language. Please note: the developer and maintainer of those routines takes on the role of tool maker; tool users just use what they're given (and complain when it doesn't work right). This is key.
Python seems part way along that path. I always thought its object orientation was a stumbling block to achieving it, because its OO support is ungainly, half-baked and awkward. It turns out that most non-professional Python programmers never define their own classes, so that's an issue that doesn't come up. But for the beginner/non-professional who becomes proficient enough to want to use classes, they are there.
I imagine the new language we're talking about being the same, but ideally without the flaws: There can be features that the beginner/non-professional might never use, but they are there in case they're wanted. The language should thus support a continuous spectrum of developers -- from rank beginner non-programmers at one end to fully-capable professionals at the other -- with none of the discontinuous breaks in assumed developer ability (or target language) that are inevitably be created by defining a 4GL with "escapes" to (a) 3GL(s).
For context, here is 'hello world':
Java:
class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } }
C:#include <stdio.h> int main() { printf("Hello World!"); return 0; } Powerflex: WRITELN "Hello World!"In each case we have a 5 to one reduction in code lines, at least that in places for bugs and a focus on what is to be done, not comiler cruft. Shorter-safer-higher.
That's an example usually used to illustrate how C and Java (or C#, just change some capitalisation) are verbose (and therefore wrong) whilst Python or Ruby or JavaScript or <insert language here> are so right.
Of course, they don't mention that:
- The Java/C#-ish example embodies the Java/C# philosophy of everything-in-a-class, so main (or Main) is defined in a class, and any or multiple classes can be program entry points in a given project; or
- The C example is helpfully explicit about the header file that defines 'printf' (and it's not strictly required in this case), and it clearly shows that main() is a function that returns a value, which is very useful when integrating C programs with shell/Python/whatever scripts to invoke them; or
- The (usually Python or Ruby or JavaScript) Powerflex code doesn't indicate the entry point at all, so fundamental semantic information is missing; or
- A typical developer might never specify a main (or Main) entry point in their entire careers, either because they use a framework that defines it internally or they never start a project from scratch.
That said, I appreciate the value of clarity and I'm not sure the C or Java/C#-ish examples are particularly clear, and there are no doubt better ways of specifying "this is the (or a) entry point."
But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
What I'm on about is separating tool building from tool use: making it way easier to create, maintain and extend the LYN. APL is a super example of the LYN for writing certain kinds of mathematical expressions, hampered by some awkward choices of symbols. We should be able to create a 'New APL' easily to replace it, but we can't.
This is mostly an aside, but there is a 'New APL'. It's called J, designed and implemented in part by the same Ken Iverson who invented APL.
From jsoftware.com: "J is a high-level, general-purpose programming language that is particularly suited to the mathematical, statistical, and logical analysis of data. [...] Jd ( J database) is a high-performance columnar RDBMS written in J that is geared toward storing and analyzing large amounts of data. Jd is free for non-commercial use. Jd lives openly and dynamically in the J execution and development environment, so that the full power of J is available to the application developer. For example, Jd columns are mapped to J nouns, so built-in J primitives can apply directly to the data."
Sounds like it might be just what you're looking for.
Yes, I know about J. It's on my list of languages I need to try. But it's not on the meta-programming path.
Ditto for 4GLs, like dBase and Powerflex.
I don't know about Powerflex or Dataflex (which I understand it resembles?) but in the 1980's I created some utilities (in assembly language -- they were Terminate-and-Stay-Resident utilities, back when those were a thing) for a consultant who used Dataflex.
I think that highlights one of the limitations of such languages, which is that its developers inevitably want functionality that they'd like to have been able to create within the language, but couldn't.
(Well, maybe not TSR utilities, as those were a special category of hack, but the principle is good -- the language should be capable, within reason, of doing whatever a developer might want even if the average developer can't.)
Yes, Powerflex is historically compatible with Dataflex, but diverged from it long ago. A skilled programmer can write just about any application program, including Window API access and forms, Web client and server, Unix portable, SQL hosted and queries, COM objects, mountains of stuff. And very substantial meta-programming, via type-sensitive macros with compile-time arithmetic. I had a lot of fun building it, but I don't like programming in it, for all the usual reasons.
It sounds like it has the right semantics. Why not change the syntax so it's more appealing?
Isn't that just a 'new' 4GL by another name?
Maybe, but I'm not convinced that "maps readily unto the underlying 3GL" is anywhere near as good as "3GL with zero accidental complexity, that can fully express the things that need to be done for business purpose via syntactically-friendly libraries, is maintainable and extensible as needed, and achieves what the user likes."
I don't see the distinction, but you did give yourself a challenge: how will you fulfil these aims other than by the kind of language MP extension outlined above?
"What the user likes" is a (maybe the) key ingredient, and it isn't necessarily shorter, safer (sigh -- I have many debates with proponents of dynamic typing), or higher. It might include (or be) other qualities -- like fun to use -- that are much more persuasive in getting users to switch from whatever they use now.
The user likes to get the job done, without pain or undue effort. Other than resisting change, I don't see anyone arguing against shorter-safer-higher. The question is how.
The user likes what's fun. Observation of hundreds of business users over the years tells me that whilst pain and undue effort negatively affect tool appeal, merely being painless and effortless is not enough to make a tool appealing.
It needs to be fun.
Something quite notable about Python is the degree to which beginner or otherwise non-professional programmers will spend endless hours attempting to get buggy Python code working, and enjoy it.
There's a similar enjoyment I've observed in Excel users. They may be, at best, marginally productive, but as long as they're having fun, it's good.
My thesis is that writing less code with less bugs and getting more useful output in less time is just as much fun. So I'll make a proposal as a separate post.
I think fun is quite a bit more than that.
Quote from dandl on March 18, 2021, 5:26 amJS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Of course, but that's what we were discussing: IU/UX, HTML, CSS. JS is everywhere in that world, enterprise or no. And most of what I see there is frameworks, transpiling, React/Angular. The CSS is heavily reused across forms to get the corporate style, and the HTML is generated as JSX, JQuery, etc. Lots of Wordpress, Magento, Foursquare, stuff like that. There may be people still hand-crafting full static pages in raw HTML/CSS, but I haven't met one in years.
But this is off the point. We're supposed to be talking about programmer tools and a language after D, and this is not it.
JS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Of course, but that's what we were discussing: IU/UX, HTML, CSS. JS is everywhere in that world, enterprise or no. And most of what I see there is frameworks, transpiling, React/Angular. The CSS is heavily reused across forms to get the corporate style, and the HTML is generated as JSX, JQuery, etc. Lots of Wordpress, Magento, Foursquare, stuff like that. There may be people still hand-crafting full static pages in raw HTML/CSS, but I haven't met one in years.
But this is off the point. We're supposed to be talking about programmer tools and a language after D, and this is not it.
Quote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Again, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Quote from Dave Voorhis on March 18, 2021, 2:29 pmQuote from dandl on March 18, 2021, 5:26 amJS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Of course, but that's what we were discussing: IU/UX, HTML, CSS. JS is everywhere in that world, enterprise or no. And most of what I see there is frameworks, transpiling, React/Angular. The CSS is heavily reused across forms to get the corporate style, and the HTML is generated as JSX, JQuery, etc. Lots of Wordpress, Magento, Foursquare, stuff like that. There may be people still hand-crafting full static pages in raw HTML/CSS, but I haven't met one in years.
There's a lot of hand-crafted HTML/CSS in the UI/UX design space.
There's a lot of JavaScript too, but it's almost all front-end and nothing else. All the real work is behind it, and it's not JavaScript.
Front-end is sometimes treated like it's everything, but it's not.
But this is off the point. We're supposed to be talking about programmer tools and a language after D, and this is not it.
Front-ends aren't part of it?
Quote from dandl on March 18, 2021, 5:26 amJS is the assembly language of the browser, along with HTML and CSS. In my world, all modern web sites used JS. Mostly it's transpiled down to ES5, and often it starts out as TypeScript or CoffeeScript or ES6. All of them suffer from the same problem as Java: lots of accidental complexity, lots of cruft.
Yes, it's always in Web front-ends. I mean behind the Website, on the server side, where aside from Node to instrument Docker containers and the like, you barely see it.
Of course, but that's what we were discussing: IU/UX, HTML, CSS. JS is everywhere in that world, enterprise or no. And most of what I see there is frameworks, transpiling, React/Angular. The CSS is heavily reused across forms to get the corporate style, and the HTML is generated as JSX, JQuery, etc. Lots of Wordpress, Magento, Foursquare, stuff like that. There may be people still hand-crafting full static pages in raw HTML/CSS, but I haven't met one in years.
There's a lot of hand-crafted HTML/CSS in the UI/UX design space.
There's a lot of JavaScript too, but it's almost all front-end and nothing else. All the real work is behind it, and it's not JavaScript.
Front-end is sometimes treated like it's everything, but it's not.
But this is off the point. We're supposed to be talking about programmer tools and a language after D, and this is not it.
Front-ends aren't part of it?
Quote from Dave Voorhis on March 18, 2021, 2:39 pmQuote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
--
1 - https://projectlombok.org/
Quote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
--
1 - https://projectlombok.org/
Quote from dandl on March 19, 2021, 1:24 amQuote from Dave Voorhis on March 18, 2021, 2:39 pmQuote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
There is an implied outer block comprising all the lines of code not inside a function/procedure.
I should have mentioned: Powerflex has a Turing-complete (recursive) macro pre-processor. When I first ported the real mode compiler to protected mode, I needed a really big program to test it. So I wrote a 10 line macro program that expanded into 1 million lines of code. It took nearly a minute to compile on a 10MHz AT. We lost something valuable now that our languages can no longer do that.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
Yes, I know Lombok. It's an island near Bali, distinguished by having totally different flora and fauna (the Wallace Line). I always thought that an odd choice of name for a Java extension.
As I understand it, the essence of annotations (as with C# attributes) is to attach metadata to things for code to interact with at runtime. They're not well suited to what I have in mind.
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
C++ has templates for a very specific purpose: STL. They allow an algorithm to be specialised across types, but they fall well short of what I had in mind.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
I rewrote the Andl compiler using Pegasus, a PEG parser that emits C# code. It's nice to be able to debug directly into the underlying C#, but the tech required to create a compiler like that is way too hard for most. New languages are tough, and need to be created by degrees, experimentally. Transpilers are tough to write and hard to maintain/modify. We need a better way.
But why not take the core idea of macro expansion and use it to front end Java code? Or has someone already done that?
Just to be clear: adding a TTM-like RA to Java should be an acid test of this approach. Java is well able to express the necessary logic, but at the cost of much boiler-plate and runtime type checking. A good enough meta-programming front-end should do both. But right now I don't know how to do that.
Quote from Dave Voorhis on March 18, 2021, 2:39 pmQuote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
There is an implied outer block comprising all the lines of code not inside a function/procedure.
I should have mentioned: Powerflex has a Turing-complete (recursive) macro pre-processor. When I first ported the real mode compiler to protected mode, I needed a really big program to test it. So I wrote a 10 line macro program that expanded into 1 million lines of code. It took nearly a minute to compile on a 10MHz AT. We lost something valuable now that our languages can no longer do that.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
Yes, I know Lombok. It's an island near Bali, distinguished by having totally different flora and fauna (the Wallace Line). I always thought that an odd choice of name for a Java extension.
As I understand it, the essence of annotations (as with C# attributes) is to attach metadata to things for code to interact with at runtime. They're not well suited to what I have in mind.
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
C++ has templates for a very specific purpose: STL. They allow an algorithm to be specialised across types, but they fall well short of what I had in mind.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
I rewrote the Andl compiler using Pegasus, a PEG parser that emits C# code. It's nice to be able to debug directly into the underlying C#, but the tech required to create a compiler like that is way too hard for most. New languages are tough, and need to be created by degrees, experimentally. Transpilers are tough to write and hard to maintain/modify. We need a better way.
But why not take the core idea of macro expansion and use it to front end Java code? Or has someone already done that?
Just to be clear: adding a TTM-like RA to Java should be an acid test of this approach. Java is well able to express the necessary logic, but at the cost of much boiler-plate and runtime type checking. A good enough meta-programming front-end should do both. But right now I don't know how to do that.
Quote from Dave Voorhis on March 21, 2021, 6:04 pmQuote from dandl on March 19, 2021, 1:24 amQuote from Dave Voorhis on March 18, 2021, 2:39 pmQuote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
There is an implied outer block comprising all the lines of code not inside a function/procedure.
If there are multiple such files, which one does it run first?
I should have mentioned: Powerflex has a Turing-complete (recursive) macro pre-processor. When I first ported the real mode compiler to protected mode, I needed a really big program to test it. So I wrote a 10 line macro program that expanded into 1 million lines of code. It took nearly a minute to compile on a 10MHz AT. We lost something valuable now that our languages can no longer do that.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
Yes, I know Lombok. It's an island near Bali, distinguished by having totally different flora and fauna (the Wallace Line). I always thought that an odd choice of name for a Java extension.
As I understand it, the essence of annotations (as with C# attributes) is to attach metadata to things for code to interact with at runtime. They're not well suited to what I have in mind.
Indeed, the essence of annotations is supposed to be to attach metadata to code, to help things happen at runtime or at other times. For better or worse (mainly the latter, I'd say) they've grown a bit beyond that.
They can be used to generate code, as a sort-of half-baked meta-language. (Elsewhere, saying so will usually earn me a ranty response from an annotation fanboi pointing out that I'm old, don't know what I'm talking about, annotations are declarative which makes them excellent, and I should retire already and leave proper Java programming to younger and more capable developers, etc. That will inevitably draw responses from the anti-annotation brigade, and before long the forum fire department will need to be called in.)
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
C++ has templates for a very specific purpose: STL.
C++ templates predated it by a couple of years. Templates appeared in 1990 and STL in 1992, though to be fair it may be a co-fertilised history as Stepanov had apparently been working on notions of generic programming since 1979.
They allow an algorithm to be specialised across types, but they fall well short of what I had in mind.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
I rewrote the Andl compiler using Pegasus, a PEG parser that emits C# code. It's nice to be able to debug directly into the underlying C#, but the tech required to create a compiler like that is way too hard for most. New languages are tough, and need to be created by degrees, experimentally. Transpilers are tough to write and hard to maintain/modify. We need a better way.
But why not take the core idea of macro expansion and use it to front end Java code? Or has someone already done that?
Simple macro expansion is deprecated -- for reasons we've both mentioned elsewhere (see https://forum.thethirdmanifesto.com/forum/topic/life-after-d-m-for-metaprogramming/) -- but Java code generation is somewhat accepted, to the point that it's an explicit optional build step in the most popular build systems, Maven and Gradle. But it's considered best to avoid it, as it results in brittle, unmaintainable code and it forces two maintenance targets on every project: the code input to the generator, and the code generator itself. (Or three maintenance targets, if you count the rest of the application code separately.)
For example, there is Jakarta XML Binding -- aka JAXB -- that generates Java code to automate reading XML files as class instances. It's largely deprecated now.
I'm using a bit of code generation in my work-in-progress Wrapd "SQL amplifier" library that makes it easier to integrate SQL DBMS querying into Java in general and Java Streams in particular.
With both JAXB and Wrapd, the goal is to make it easier to use Java with existing external data format definitions. The goal is not to replace Java programming with writing some simplified non-Java.
Indeed, I think needing pure macro expansion to replace/generate Java either indicates a serious limitation of Java (which, in terms of implementing TTM type-system semantics, it has), and/or it indicates some serious limitation of the developer for whom it is intended. In either case, I'm not sure a macro system is the solution.
Just to be clear: adding a TTM-like RA to Java should be an acid test of this approach. Java is well able to express the necessary logic, but at the cost of much boiler-plate and runtime type checking. A good enough meta-programming front-end should do both. But right now I don't know how to do that.
It's notionally straightforward to generate code, but I can't see how it solves the usual structural vs nominal typing issues for tuple and relation types.
For that, I think a transpiler or even a compiler may be more appropriate. Of course, that brings up all the usual issues of wanting/needing to create a hefty toolchain including debugger support, IDE plugins, etc., to make it of any production use.
As an aside, a few years ago I wrote (for use as examples in a class I was teaching) a to-Java transpiler for a simple JavaScript-like language, with semantics not found in Java (dynamically typed with nestable functions) to prevent it simply being syntax translation. The effort was rather non-trivial, at least for a small, over-several-evenings project. Transpiling to languages of notionally-equivalent "level" -- 3GL to 3GL -- but different semantics is hard, fraught with gotchas, and is somewhat toilsome. Compiling down a "level" -- 3GL to 1 or 2GL -- is arguably easier. Aside over.
Perhaps a more reasonable alternative, at least in terms of the TTM type-system semantics, is to dispense with the TTM type-system and work within the semantic limitations of Java (or whatever host language.) That's essentially what I've done / am doing with my Wrapd library.
But then, this (part of the) discussion started as a result of specifically not wanting to focus on practical production but instead focus on what the ideal, perhaps purely fantasy general purpose language to support creating a D should be like. Again, I think it would be interesting to focus on the language itself -- this being an opportunity to dispense with both the cruft that catches out beginners, and the cruft that us experienced developers don't like -- and then look at how to implement it. Whether that turns out to be simple macro expansion for Java/C#/whatever or a full-fledged compiler or something else, is something to be determined once the language design is (more) in hand.
Quote from dandl on March 19, 2021, 1:24 amQuote from Dave Voorhis on March 18, 2021, 2:39 pmQuote from dandl on March 18, 2021, 5:52 amAgain, the distinction doesn't matter. Is a developer who makes a code generator for himself any different from a developer who makes a code generator for his colleagues? Or for his colleagues in other companies?
Not really.
Totally. It's about specialisation. A tool made to solve an immediate problem (a Bash script to fix text) provides a productivity boost over editing by hand. A tool made to solve a class of problems (Bash itself) provides an enormous boost for many users. Most people can't and don't build tools for repeated use; they depend on those who do.But per that consideration, the Powerflex example isn't particularly clear, either. It doesn't show where the entry point is at all, so is it specified elsewhere?
What entry point? It just executes the code, top to bottom. Everything else is accidental complexity. Run the program, get the answer. Period.
So is every Powerflex program only a single file, like a bash script?
No separate compilation, libraries or modules?
Powerflex has programs, modules and functions, but limited types. Like many 4GLs, forms and database files exist as types within the program. It can call Windows DLLs and COM objects, much like Python.
It has better separate compilation than most languages, as programs can easily be recompiled and replaced in a running system, because compiled programs are separate files.
Cool. So back to the point: how do you specify the entry point to a Powerflex program?
There is an implied outer block comprising all the lines of code not inside a function/procedure.
If there are multiple such files, which one does it run first?
I should have mentioned: Powerflex has a Turing-complete (recursive) macro pre-processor. When I first ported the real mode compiler to protected mode, I needed a really big program to test it. So I wrote a 10 line macro program that expanded into 1 million lines of code. It took nearly a minute to compile on a 10MHz AT. We lost something valuable now that our languages can no longer do that.
Or is every source file an implicit at-the-top entry point (and thus which script acts as the entry point is specified elsewhere?)?
Merely eliding semantics, only to place them elsewhere, is a false "shorter."
Thus, I prefer clarity to merely being "shorter."
This is my core theme. For this purpose let us assume an underlying Java host language and JVM (the features of C# add nothing to this argument). The question is how to add meta-programming on top of Java as templates were added on top of C++, so that 'hello world' becomes a one liner. [As an aside, the macros in C can do a lot of this and are sorely missed. They are also a major source of hard bugs, so we're not going there.]
So the aims of Java-MP are:
- Construction of a DSL from within the language (not by implementing a new compiler)
- Code reduction of 5:1 or better, zero accidental complexity
- Discoverable, so it can be used by a naive programer with minimal training or documentation
- Fully type safe, with full discovery on compile-time errors
- Multiple syntax options, not constrained by the host language (syntactical templates)
- Open-closed principle: open for extension, closed from modification
- Debuggable in the DSL, optional access to underlying Java code
Doesn't sound too hard, does it?
That might be a transpiler to Java, assuming you don't define a transpiler as a compiler.
Transpiling languages with almost identical semantics is easy; it's mostly syntactic conversion. Transpiling languages with different semantics can be very hard. I've written a few transpilers, mostly for pedagogy, and it's surprisingly challenging.
I suspect directly compiling to the JVM -- generating bytecode -- or running as an interpreter might be easier (though it is a new compiler.)
Aside from "multiple syntax options", you've essentially described Kotlin. Or Groovy. Or any of the other JVM languages.
I like "Discoverable," though I've found over the years that whilst skilled programmers can easily distinguish intuitive from non-intuitive things for programmers, for non-programmers doing programming there is no such thing as intuitive. It's all equally baffling.
So the ways you've tried didn't work for you, so we won't try it that way. And no, this is nothing like any JVM language. Here is Kotlin:
fun main(args : Array<String>) { println("Hello, World!") }
Still too much cruft.
I don't see any semantic cruft. If you need to identify the entry point in a multi-file program and it can accept command-line arguments, that's pretty much the minimum if you don't want to rely on "magic" implicit definitions (If I recall correctly, Ruby has these; I think it's awful but some like it.)
There is syntactic cruft. The "fun" keyword and most or all of the ":", "{", "}", "(", ")", "<", ">" punctuation could go, maybe relying on smart indentation or maybe not needing it, if the grammar is otherwise unambiguous (though it's very likely ambiguous without it.)
Does that result in a pleasingly-terse and readable language, or a hard-to-read one?
Striking a suitable balance between the two requires some experimentation with syntax and grammars.
The point about it is to make that experimentation plausible and accessible to tool builders without the high entry cost of writing a compiler. I looked for an example and found this: https://vladmihalcea.com/java-records-guide/. It shows the difference between Java records old style and new style. I'm talking about language extensions that allow anyone to create 'new style' for any part of the language, not just what the Java committee hands out.
Java has annotations, which have been used heavily for this sort of thing, though some (I'm one of them) argue it's used -- read, misused -- too heavily for some things. E.g., see Java Spring.
Notably, one of the useful and arguably right-sized uses of Java annotations is a tool called Lombok1, which (among other things) effectively provided Java records before Java had records.
Yes, I know Lombok. It's an island near Bali, distinguished by having totally different flora and fauna (the Wallace Line). I always thought that an odd choice of name for a Java extension.
As I understand it, the essence of annotations (as with C# attributes) is to attach metadata to things for code to interact with at runtime. They're not well suited to what I have in mind.
Indeed, the essence of annotations is supposed to be to attach metadata to code, to help things happen at runtime or at other times. For better or worse (mainly the latter, I'd say) they've grown a bit beyond that.
They can be used to generate code, as a sort-of half-baked meta-language. (Elsewhere, saying so will usually earn me a ranty response from an annotation fanboi pointing out that I'm old, don't know what I'm talking about, annotations are declarative which makes them excellent, and I should retire already and leave proper Java programming to younger and more capable developers, etc. That will inevitably draw responses from the anti-annotation brigade, and before long the forum fire department will need to be called in.)
The step beyond that is template metaprogramming, which has its own issues as we know from its use in C++.
C++ has templates for a very specific purpose: STL.
C++ templates predated it by a couple of years. Templates appeared in 1990 and STL in 1992, though to be fair it may be a co-fertilised history as Stepanov had apparently been working on notions of generic programming since 1979.
They allow an algorithm to be specialised across types, but they fall well short of what I had in mind.
And that's essentially a first step to full transpilation, which is needed if you're not just wrapping semantics but shifting to new semantics -- particularly if some of the new semantics are incompatible with the host language semantics. When much of the semantics are different, full compilation may be easier.
It's probably best to start with the ideal language, then work backward from it to a host language to see whether libraries, language-specific facilities like annotations, templates, transpilation, or compilation are most appropriate.
I rewrote the Andl compiler using Pegasus, a PEG parser that emits C# code. It's nice to be able to debug directly into the underlying C#, but the tech required to create a compiler like that is way too hard for most. New languages are tough, and need to be created by degrees, experimentally. Transpilers are tough to write and hard to maintain/modify. We need a better way.
But why not take the core idea of macro expansion and use it to front end Java code? Or has someone already done that?
Simple macro expansion is deprecated -- for reasons we've both mentioned elsewhere (see https://forum.thethirdmanifesto.com/forum/topic/life-after-d-m-for-metaprogramming/) -- but Java code generation is somewhat accepted, to the point that it's an explicit optional build step in the most popular build systems, Maven and Gradle. But it's considered best to avoid it, as it results in brittle, unmaintainable code and it forces two maintenance targets on every project: the code input to the generator, and the code generator itself. (Or three maintenance targets, if you count the rest of the application code separately.)
For example, there is Jakarta XML Binding -- aka JAXB -- that generates Java code to automate reading XML files as class instances. It's largely deprecated now.
I'm using a bit of code generation in my work-in-progress Wrapd "SQL amplifier" library that makes it easier to integrate SQL DBMS querying into Java in general and Java Streams in particular.
With both JAXB and Wrapd, the goal is to make it easier to use Java with existing external data format definitions. The goal is not to replace Java programming with writing some simplified non-Java.
Indeed, I think needing pure macro expansion to replace/generate Java either indicates a serious limitation of Java (which, in terms of implementing TTM type-system semantics, it has), and/or it indicates some serious limitation of the developer for whom it is intended. In either case, I'm not sure a macro system is the solution.
Just to be clear: adding a TTM-like RA to Java should be an acid test of this approach. Java is well able to express the necessary logic, but at the cost of much boiler-plate and runtime type checking. A good enough meta-programming front-end should do both. But right now I don't know how to do that.
It's notionally straightforward to generate code, but I can't see how it solves the usual structural vs nominal typing issues for tuple and relation types.
For that, I think a transpiler or even a compiler may be more appropriate. Of course, that brings up all the usual issues of wanting/needing to create a hefty toolchain including debugger support, IDE plugins, etc., to make it of any production use.
As an aside, a few years ago I wrote (for use as examples in a class I was teaching) a to-Java transpiler for a simple JavaScript-like language, with semantics not found in Java (dynamically typed with nestable functions) to prevent it simply being syntax translation. The effort was rather non-trivial, at least for a small, over-several-evenings project. Transpiling to languages of notionally-equivalent "level" -- 3GL to 3GL -- but different semantics is hard, fraught with gotchas, and is somewhat toilsome. Compiling down a "level" -- 3GL to 1 or 2GL -- is arguably easier. Aside over.
Perhaps a more reasonable alternative, at least in terms of the TTM type-system semantics, is to dispense with the TTM type-system and work within the semantic limitations of Java (or whatever host language.) That's essentially what I've done / am doing with my Wrapd library.
But then, this (part of the) discussion started as a result of specifically not wanting to focus on practical production but instead focus on what the ideal, perhaps purely fantasy general purpose language to support creating a D should be like. Again, I think it would be interesting to focus on the language itself -- this being an opportunity to dispense with both the cruft that catches out beginners, and the cruft that us experienced developers don't like -- and then look at how to implement it. Whether that turns out to be simple macro expansion for Java/C#/whatever or a full-fledged compiler or something else, is something to be determined once the language design is (more) in hand.