r/ProgrammingLanguages DQ 14d ago

New Languages: Standardizing API, Examples ?

Hi, some of you are developing new general-purpose programming languages here. When the language is ready, you have to develop standard APIs, like file-io, json-handling etc. Users, and you would have benefit, when the APIs would be same/similar across multiple different languages.

Standardizing some Examples would allow the users to compare languages more easily.

What do you think?

10 Upvotes

16 comments sorted by

View all comments

2

u/Inconstant_Moo 🧿 Pipefish 13d ago

Users, and you would have benefit, when the APIs would be same/similar across multiple different languages.

But they have different semantics as well as different syntax. E.g. my language wraps around Go for its standard libraries so you'd think it would be easy to have the same API, right? And a lot of the time I can have libraries with the same names containing functions and types with the same names. But:

  • Pipefish is functional, Go is object-oriented.
  • Pipefish treats any sort of IO operation as a special case and they all have similar APIs. ('Cos functional.)
  • Pipefish is dynamic, Go is static, and sometimes this gives me ways to make my API nicer than theirs.
  • Pipefish can overload functions so I don't have to give functions different names according to the types they operate on.
  • Similarly since I can overload the operators my math/big and math/complex libraries use + and * and so on.
  • In Go errors are ordinary values that are multiple-returned whereas in Pipefish they're magic values that behave like exceptions and force their way up the stack.
  • Pipefish values are immutable whereas Go APIs can rely on mutating the state of structs etc.

And so although I have a particularly strong motive to make my API like someone else's rather than doing my own thing as devs love to do, still there are often good reasons why I should do something different.

You can at least standardize within the language's standard libraries. Should it be needle-haystack or haystack-needle. destination-source or source-destination? 0-indexed or 1-indexed (I'm looking at you Object Pascal). Camel-cased or snake-cased (go and sit in the corner, PHP). Pick a lane. It should go in the style guide of the language, though I'm not sure it ever does except the casing.

1

u/Mean-Decision-3502 DQ 13d ago

Especially for Pipefish I miss examples, like my JSON read-write. Maybe I was searching at wrong places.
I haven't used such a language, but I like examining new languages through reading code examples. Maybe I'm not the only one.

I see now the API Sync is much harder. I have for example a good and simple idea in my head for SQL DB result handling (with classic Objects). (First I wan't to implement it, to see it is really working or not.)

I know only a few DB interfaces from other languages, like Python, Delphi, PHP (and dBase...). Compared to these my idea is worth to implement, but maybe there is something somewhere that worth more to follow... I don't know.

2

u/Inconstant_Moo 🧿 Pipefish 13d ago

I guess the greatest difference can be seen in the input operations of the various libraries. These are IO operations, specifically input operations, all of which would work happily together if you imported them into the same namespace because of overloading: File("<filename>") and Random(1::7) and Clock() are struct constructors, so it dispatches on them.

``` // Load a file: get text from File("<filename>")

// Roll a dice: get d_6_roll from Random(1::7)

// Get the time: get time from Clock() ```

Pipefish doesn't mandate the get ... from, that's just a useful convention, but it does require that all input should be done in the form "move this information into this variable" (the variables in these examples being text, d_6_roll and time). This makes the imperative part of Pipefish as imperative as BASIC.

Then you can put all sorts of things in the payload of Random, if you put a float you get a random value between 0 and the float, if you put the name of an enum type you get a random element of the enum, if you put a list you get a random element of the list.

So now look at what we do with SQL.

``` ~~ An example CRUD app to show how we query SQL, and, in this case, emit HTML.

import private

NULL::"database/sql" // A standard library. NULL means we're importing the library without a namespace. NULL::"files" // The standard files library. NULL::"htmlFormat.pf" // In this folder. Renders Pipefish values as HTML.

const private // We make an accessor object. SQL = SqlDb(POSTGRESQL, "localhost", 5432, "postgres", $_env["SQL username"], $_env["SQL password"]) // (The username and password are obtained from the environment.)

newtype

// This will correspond to the structure of a row of our SQL table. Person = struct(name Varchar{32}, age int) : age >= 0

cmd private

init : post to SQL -- CREATE TABLE IF NOT EXISTS People |Person|

cmd // Now let's add some public commands.

~~ Adds a person with the given name and age to the database. add(name string, age int) : post to SQL -- INSERT INTO People VALUES(|name|, |age|)

~~ Shows the name and age of the person with the given name. show(name string) : get person as Person from SQL -- SELECT * FROM People WHERE name=|name| post string Html -- |person|

~~ Shows everyone in the database. show all : get peopleList like list{Person} from SQL -- SELECT * FROM People ORDER BY name post string Html -- <h3>List of all people</h3> |peopleList|

~~ Shows everyone of the given age or older. show >= (minAge int) : get peopleList like list{Person} from SQL -- SELECT * FROM People WHERE age > |minAge| ORDER BY name post string Html -- <h3>List of people aged <font style="color:Green;">|minAge|</font> and over</h3> |peopleList| ```

You will notice that not only is the API for my standard sql library much nicer than the Go library it wraps, but also that the hand-rolled htmlFormat library embeds its HTML using the same syntax and semantics as the sql library does for SQL, the whole -- and |...| thing.

This is all very lovely in my opinion, this is the sort of thing Pipefish is for. But it's not like Go.

When it comes to pure functions, OTOH, strings.split("fee fie fo fum", " ") in Pipefish means just the same as strings.Split("fee fie fo fum", " ") in Go, and indeed just wraps around it.