Skip to content

Comment on Bog – small, strongly typed, embeddable language

Comments

Thank you for posting this.

let {print} = import "std.io"

An idea obvious in hindsight that I hadn't thought before - if import returns an environment and let can destructure, then a pattern match can bind an explicit subset of that import. Something like:

`(let {print read} (import io) (print (read)))`

Further down I find essentially that example (with input instead of read) and destructuring assignment within function arguments:

`let add = fn ((a,b)) a + b`

though the grammar suggests that {} is initialisation and not a map/dict/hash/assoc/environment style thing, so you probably don't have `fn ({key value}) value + 4` or similar for taking maps apart as they are passed to a function. Thus I think import is special cased.

The bytecode layer knows what maps are though, so maybe they're just missing from the syntax

Funny, I find this syntax very obtuse: it looks to me like "print" is being defined as, well, the print function, through a very roundabout name collision. What happens if there is a typo and the code says: let {ptint} =... What error message comes up?

"Obtuse" is maybe not the word you were looking for. Opaque perhaps?

This kind of destructuring syntax is common in many newish languages -- Rust, Clojure, newer flavors of JS, Typescript, etc -- and becomes second nature pretty quickly. What you're seeing is really two things: first that you can pull apart a map as part of assignment, and second that there's sugar to name the variable after the map key.

In JS, you could write:

     const { foo: bar } = something
     
And that's sugar for
     const bar = something.foo
At the same time, JS many other languages have pervasive support for the idea that often you want the same name for a variable as the map key where you're going to use it. So, e.g.
     const mapOfFoo = { foo }
is equivalent to
     const mapOfFoo = { foo: foo }
Combining these things, you get:
    const { foo } = something
Equivalent to
    const foo = something.foo
i.e. the variable/property auto-aliasing works in the destructure too. When you consider that you are importing a big object with a bunch of fields and functions hung off of it, it becomes natural for that to work the same way:
    import { foo } from "someplace"
I'd argue that it's not actually opaque, let alone obtuse; it's merely unfamiliar because it's (I'm guessing) a combination of unfamiliar syntactical motifs. But as you get more familiar with that kind of syntax, you'll find it natural, and would be surprised if, say, it worked for regular objects but not in imports. When I picked up Rust, for example, I found myself right at home with it (same for the pattern-matching assignment stuff, which feels very similar to Clojure's).

As for errors, you'd get the same error as in the desugared version: ptint is not a property on the object it's pulling apart.

Well I can't test it in bog, but TypeScript allows exactly this syntax and it will give you an error like "Property ptint does not exist on type ..."

One would imagine that

  let {print} = import "std.io"
is equivalent to
  let print = (import "std.io").print

It's not roundabout. Namespaces in many languages are simply dictionaries/mappings of strings to objects, with the restriction that the strings must conform to a variable name standard.

There's not much difference between `obj.attr` and `obj['attr']`.

This is bog standard javascript these days.

Something I hate about about c is that you don't know where the hell somefunc() came from.

Some languages have foo.somefunc() which I think works quite well although iffooisrealllylong.function() is a risk.

I suppose this gets you the best of both worlds.

Although using let does seem a bit weird to me. It seems conceptually misleading.

Something I hate about about c is that you don't know where the hell somefunc() came from.

I think you mean something you hate about not using an IDE with the language. One can do `from onoz import *` in python and Java to have a similar "wait, where did do_magic() come from?" experience, and then Scala will see your wildcard import and raise you implicit methods, which can die in a raging fire tornado

I think you mean something you hate about not using an IDE with the language

Well it's a 'feature' of the language so the criticism still stands. Ides could solve a lot of language warts but we still rightfully criticise the language for the warts. C's lack of memory safety could be solved by good programming practices, but we still criticise c for the lack of memory safety.

This is true that there is no language feature to enforce this. But this can be worked around by enforcing naming functions with adequate prefixes, which is a very common approach, if not a best practice.

Isn't this exactly what CommonJS does/did?

No, you're thinking of `destructuring`. CommonJS was "just" a common format for defining/importing modules in a NodeJS environment (via `module.exports` and `require`), eventually being used for packaging frontend "applications" as well, popularized by Browserify.

To expand, the following was common before destructuring but with CommonJS:

    var some_func= require('some_module').some_func
Which, as you know, would probably usually be done like this today, where we have destructuring:
    let {some_func} = require('some_module')

This Syntax has the flaw that autocomplete cannot assist you before the from import clause has been added...

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.