Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You mean Python, not Clojure. A number of key underpinnings, such as (almost) exclusively immutable datastructures are missing from this language.

It is more of a Python with a LISP syntax.



If anything it’s major inspirations seem to be Clojure and Lua.

It has some of the affordances of the former in terms of semantics, but is stripped down and friendly like Lua.

The use cases also seem to overlap with Lua, as a fast, embeddable scripting language that you can easily keep in your head (see docs).

It seems to be simpler than Lua because it doesn’t complect arrays and dicts into tables, as arrays are a separate construct. And it affords you with immutable versions of those.

To me it looks like a Clojure-like for Lua use cases.


The Lua similarity is not exactly a coincidence, the author of Janet also previously created Fennel[0], a Lisp for Lua. [0]: https://fennel-lang.org/


I'm pretty sure GP meant Closure, considering the language has matching immutable data structures for mutable ones [^1] and even its own (limited) version of EDN called JDN. It’s definitely also inspired by it.

[^1]: https://janet-lang.org/docs/data_structures/index.html


> I'm pretty sure GP meant Closure

Closure is not a language so hopefully not?

> the language has matching immutable data structures for mutable ones [^1]

Looking at the lingo being used, the extremely limited breadth of ABI, and the complexity they assert around "immutable" data structures, they're clearly imperative data structures you can't mutate rather than the persistent data structures you'd expect from a strong clj inspiration.

This page looks a lot more like a description of python datatypes than clojure, the only bit that Python lacks is an official frozendict.


> Closure is not a language so hopefully not?

Very true, the typo is strong in this one.

> rather than the persistent data structures you'd expect from a strong clj inspiration

What do you mean by persistent here? I assume some kind of shared memory instead of copying? Or something with more practical implications like deep immutability?

> looks a lot more like a description of Python datatypes

I am surprised where this sentiment comes from. Because of the initial comment? Basically any language nowadays has maps, sequences and byte strings. If I had to draw a similarity to Python it would be something along the lines of first-class generators.


> What do you mean by persistent here?

I mean the class of data structures called persistent: https://en.wikipedia.org/wiki/Persistent_data_structure

> I assume some kind of shared memory instead of copying?

Sure.

> I am surprised where this sentiment comes from. Because of the initial comment?

Because "tuple" for an immutable sequence is rather specific to Python.

And data structures related to clojure (or functional languages in general) would have some sort of logarithmic component because they'd be tree-based. Pretty much the only O(1) operation in functional data structures is prepending to a linked list.


Thanks for clarifying, I did not find anything decisive searching persistent in combination with Clojure, weird.

> Because "tuple" for an immutable sequence is rather specific to Python.

As someone with a background in Swift, Rust and C#, all of which have the concept of a tuple, I did not make that connection, but thanks again.


> As someone with a background in Swift, Rust and C#, all of which have the concept of a tuple

They all have tuples, but AFAIK in none of them is a tuple a sequence (well not sure about C# it might be there, but I'd be surprised). Usually a tuple is a form of lightweight, anonymous, structure, so it's addressed by field (even if the fields are positions), you usually can't iterate through tuples, or "index" them using runtime variables (except through reflection).

That it is so in Python is somewhat peculiar, but makes sense within the context of the language (unpacking works on iterables, and thus sequences).


The .NET Tuple types Tuple<T1,…> and ValueTuple<T1,…> are not sequences — though the ITuple interface does enable item access by index without reflection — and ValueTuple<T1,…> instances are mutable, but .NET actually has two different immutable sequence types, ImmutableArray<T> and ImmutableList<T>, which are functionally similar but have different performance characteristics[1].

Along with the rest of the .NET immutable collection types[2], both are persistent data structures in the sense noted above.

In contrast, .NET tuple types are, as you say, lightweight, anonymous structures addressed by field. The ValueTuple<T1,…> types, in particular, are used in the underlying implementation of the C# tuple language feature[3].

AFAIK, Python has no built-in anonymous mutable structure types, though since type names in Python are basically only used for display purposes, you can easily create them at runtime, e.g.,

    def anon(**kwargs):
        class _:
            __slots__ = tuple(kwargs.keys())
    
            def __repr__(self):
                return 'anon(' \
                    + ', '.join((f'{i}={getattr(self, i)!r}' \
                                 for i in self.__slots__)) \
                    + ')'
    
            def __eq__(self, other):
                if not hasattr(other, '__slots__') \
                   or sorted(self.__slots__) \
                   != sorted(other.__slots__):
                    return False
                for i in self.__slots__:
                    if getattr(self, i) != getattr(other, i):
                        return False
                return True
            
        o = _()
        for k,v in kwargs.items():
            setattr(o, k, v)
        return o
    
Note that this differs in two notable ways from C# tuples:

1. Each object created has a unique type, so

    type(anon(x=1, y=2)) != type(anon(x=1, y=2))
More importantly, this means a distinct type object is created and stored for every call to anon, which could have significant performance implications at scale.

This could be easily fixed with a cache of already-created anonymous types (trading off slightly increased object-creation time, of course).

2. Equality in the above implementation is based on the equality of identically-named values rather than identically positioned values; in C#, we have

    (x: 1, y: 2) != (y: 2, x: 1)
and

    (x: 1, y: 2) == (y: 1, x: 2),
while in my implementation,

    anon(x=1, y=2) == anon(y=2, x=1)
and

    anon(x=1, y=2) != anon(y=1, x=2).
This was by choice, as it seems more intuitive; C# behavior is no more difficult to implement.

For read-only anonymous structure types, the Python standard library has namedtuple[4] (which, incidentally, bases value equality on position, not attribute name, so C#'s behavior is arguably more "Pythonic" than my own).

[1] https://learn.microsoft.com/en-us/dotnet/api/system.collecti...

[2] https://learn.microsoft.com/en-us/dotnet/api/system.collecti...

[3] https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...

[4] https://docs.python.org/3/library/collections.html#collectio...


Or python with clojure syntax?

The author also wrote fennel, a lisp/clojure-ish wrapper for lua, so I think that's the influence.


I meant Clojure. Janet's "more default looking" data structures are the immutable ones which is a pretty strong nudge. I don't see any explicit callout about data sharing for Janet but if that's really all that's missing I still feel good about citing Clojure first.


> I meant Clojure. Janet's "more default looking" data structures are the immutable ones which is a pretty strong nudge.

Except they're not immutable in the clojure sense (of persistent data structures), they're just fozen / readonly, as can be seen from their complexity bounds (and the lack of transients). And a quick check didn't show any incompatibility between the two worlds either.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: