If you created your own programming language...

It does! I wish you could specify only the 5% of the code that describes the behavior you desire. It’s not even just that the description of a behavior is verbose. It’s that many of the behaviors you have to describe could have been assumed based on common sense (programmer/system-builder common sense, not necessarily common common sense).

I have a recurring thought experiment. It’s a dialog with a computer. You say to it, “I want a chat program.” You get a chat program. You examine it, and say, “No, actually, I want 1-to-1 chat, not group chat.” You get a new chat program. You examine it and say, “No, actually, it should be peer-to-peer, not centralized.” Et cetera.

The important bit isn’t that it’s happening in natural language, because it doesn’t have to. It’s that the user is refining a system rather than constructing it. It’s a constraint satisfaction problem. The constraints are informed by human experience creating systems. 1-to-1 chat, group chat, peer-to-peer, and centralized communication are extremely common concepts, so it would be convenient to be able to use them in the specification of software.

(It’s really neat how far we’ve come. Meteor tutorials say, “Look, if you bind this table to this collection, and you bind this text box to an action that adds to the collection, you have chat!” But my question is always, “Well how am I supposed to find out about tables and collections and binding and text boxes when all I know about is chat?”)

The other important bit is that the user isn’t painstakingly repeating the same coding process as countless programmers before them. Why I ever have to write anything that’s been written thousands of times before is my eternal frustration.

I’ve gone off the deep end. Apologies. This thread started off so practical and here I’ve come and ruined it. :stuck_out_tongue:

Daily occurrence in the Haskell chat room:

  1. Someone comes in and says, “I wrote a function that works on many types of objects. How do I make the compiler accept it?”
  2. Someone answers, “In Haskell, you use GADTs for that.”
  3. One PhD later, the original asker says, “Thanks, I figured it out.”
1 Like

You’re right on the money with that observation. Initially I was going to nitpick, but I guess it’s like the Lisp quoted vs unquoted duality / universality. Turtles all the way down, etc.

I was pretty close to abusing those features in Swift to redefine how assignment worked. (For context.) I wanted a more general form of making obj2.name = obj1.name behave more like Object.defineProperty(obj2, 'name', { get: function(){ return obj1.name } }). Unfortunately you don’t seem to be able to combine autoclosures, custom operators, and inout parameters together:

// doesn't actually work, but something like this would be cool

infix operator =-= {}
func =-=(@autoclosure inout lhs: () -> Any, @autoclosure inout rhs: () -> Any) -> Any {
    // do something here
}

You actually can have { custom operator + inouts } or { custom operator + autoclosures as each operand }. Anyway, failed experiment.

That dovetails nicely with your later comment about corner-rounding / the transition from designing to maintenance.

It could be as ideal as that sounds. Like combining the accessibility of spreadsheets with a fully realized dream of JetBrains MPS or that ex-Microsoft guy’s Intentional Software metaprogramming paradigm.

Given how many people use Java, it’s not surprising that people have found delightful ways to use it, for sure.

I’ve never really formed a good understand of what dependency injection is. Either it includes a pattern of programming that I use but don’t have a name for, or it’s a pattern that I’ve never needed while programming. My only recent experience involved Angular breaking a bunch of JS semantics by doing some preprocessing on parameter names like $http… which made me just as annoyed as when I found out that PhantomJS was breaking lexical scope by using Function.toSource to basically treat your code as a string while making it look like lexical scope is preserved, because syntax highlighting still works as normal. I mean, I get the benefit, and it’s easy to get used to, but it’s like buying a car with a fake speedometer or something. Great during the sales pitch, jarring once you buy the car, and workable once you learn to just keep up with the surrounding cars.

Me too. Agreed. I often talk about liking design flexibility, etc., which generally entails lots of unsafe stuff, but I actually am supportive of safety and maintenance features. They just tend to be less interesting to talk about, IMO.

This is sort of what I wanted to do with Greg and HumanScript/etc. back in the oDesk days.

lol, I love it. :slight_smile:

The pattern is: programming with global state. Like, maybe you want to write a function like this:

function format(utcTime) {
    timeZone = TimeZone.currentTimeZone();
    locale = Locale.currentLocale();
    return DateFormatter.format(shortDateFormat(locale), utcToLocal(utcTime, timeZone));
}

That’s tricky to unit test because it references global state. Stubbing global state in a test is messy and error-prone. A more testable and flexible method looks like this:

function format(utcTime, timeZone, locale) {
    return DateFormatter.format(shortDateFormat(locale), utcToLocal(utcTime, timeZone));
}

Unfortunately, now this function is annoying to the caller, who has to provide two additional arguments every time. You’ve either passed the buck and now all the callers call the global functions, or every function all the way up the stack to main() have to now take timeZone and locale arguments.

But maybe you have a dependency injection framework that lets you write it like this:

function format(utcTime, Injected timeZone, Injected locale) {
    return DateFormatter.format(shortDateFormat(locale), utcToLocal(utcTime, timeZone));
}

The “Injected” annotation (in my made-up language) says that those arguments are optional to the caller, and will be provided automatically by the DI framework if the caller doesn’t provide them. You set up a DI context by giving it a mapping like, when a time zone is needed, provide the user’s current time zone. In a test, you’d set up the context with a fixed time zone like Eastern. In a web server, you might set up a DI context for every HTTP request with the time zone and locale of the user making the request.

Now it’s convenient for the caller, who only needs to provide the utcTime. And the function is still testable because there’s no coupling between the injected values and where they come from.

In general, it’s kinda tricky to implement this without rewriting the language. You can do it. One way you might go about it is by passing a “diContext” argument to every function. But that’s tedious and the object probably has a complicated type. You could make that argument implicit by creating a pre-processor that automatically passes the argument for you. I haven’t used Angular, but it sounds like maybe they went this route…


In the logical extreme, everything is provided by DI, including DateFormatter.format, shortDateFormat, utcToLocal, and anything else you reference. I haven’t yet looked into what anyone has written about this, but I mean to…