6 ms·
Lily: An interpreted language with a focus on expressiveness and type safety
- nickpsecurity 8y agoPrior art like Wirth's or Modula-3 language added a minimal amount of features like exceptions or some OOP on top of simple, efficient, systems languages. Usually have a GC but many prefer ref counting for efficiency. This seems like that kind of thinking in an interpreted language. Just going by what's on the front page: didn't dig deep into it or anything. Interesting project.
- weberc2 8y agoReference counting isn't more efficient than GC; usually the value of reference counting is that it's deterministic and you can bind finalizers to them (with traditional GC, finalizers run when GC runs which may not even happen). The canonical example is a file object that closes its operating system file when the object is no longer used; this is nice in theory, but as the Python folks found out, not a good substitute for properly closing files.
- nickpsecurity 8y agoOh yeah, my mistake. I should've said predictable, not efficient. I remember people liked it to avoid long pauses coming out of nowhere.
- blattimwind 8y agoWith (naive) ARC you can still get long pauses "seemingly out of nowhere", e.g. when a large object tree goes out of scope.
- Narishma 8y agoThat's not out of nowhere, since you have exact control over when it goes out of scope.
- gwking 8y agoThe other recurring example for me was OpenGL resources like textures (this was in ObjC). Again, it turned out not to work so while once I got into more complicated examples, because of ordering issues: my GLWindow instance would get deallocated, and my refcounted GLTexture class would then get finalized after the underlying CGLContext was gone, or just not the active context. I started coming up with more elaborate schemes to deal with it but then it no longer felt elegant. There is one other aspect of RC systems that I have come to appreciate but never seen anyone else write about: they play well with each other. It's fairly trivial to create foreign object wrappers for python and objective-c in both directions, that each call the appropriate refcount ops of the foreign system. You can then have allocated data structures referring back and forth across the language bridges and when you abandon the root, everything deallocates properly and deterministically in both runtimes. I do not have much experience with GC runtimes and their FFIs but from what I've read I suspect this might be trickier to reason about. This is an obscure point, but one that I did find interesting in terms of language interop.
- Narishma 8y ago> Reference counting isn't more efficient than GC Isn't it more efficient in terms of memory usage?
- koube 8y agoMaybe off topic, but I do a lot of ad-hoc python scripts where I drop scripts everywhere in my filesystem, but I need dependencies installed in a virtualenv so my ad-hoc scripts can access them. The problem I'm having is that sometimes things will run for a whole day and then fail at the end because of a typo or something. I've been looking at other languages to see if there's a language like python but type checked, or some kind of prechecking so I don't lose hours of processing to a print(str+int). I took a look at Scala but instead of virtualenv style dependency management it's more like maven projects. It has Ammonite where you can declare dependencies at the top of files but that seems kind of hacky. The other option is Python compile time checks using type hints and mypy, which I think I should eventually learn but haven't gotten around to. The Lily language looks like the closest thing to "functional type checked python" that I've seen and that's cool.
- joshbaptiste 8y agoHave a look at https://nim-lang.org https://nim-lang.org .. you might like it
- EwanToo 8y agoDepending what you want, using go run source.go gives you the compile time checks, while still giving you the source code visibility and simplicity of scripts
- koube 8y agoI took a look at Go but it seems to be more of a systems language than a scripting language and I assume that means it's less amendable to "This guy across the country needs this information in 2 hours max".
- zaphirplane 8y agoPeople say that about Go while I don’t have an opinion. I don’t understand what you mean by your example
- losvedir 8y agoOne of the bullet points is "Abstract data types (with `Option` and `Result` predefined)." I wonder if they mean "Algebraic data type", since I have seen Option/Result before as an example of those, and they're both commonly abbreviated ADTs. Or maybe they're trying to get at a concept I'm missing here?
- yaccz 8y agoADTs are not neccessary to implement Option.
- FascinatedBox 8y agoYeah, that's a mistake on my part. I pushed a fix just now. Thanks for the tip.
- _bxg1 8y agoI'm not seeing what sets this language apart. None of its features are very unique, and I believe all except garbage collection already exist in C(++). Can anyone explain what makes it interesting?
- derriz 8y agoI read the first example of Lily on the site. I found nothing offensive in the language at all - in fact there's a lot to like particularly the readability. Side rant. Unfortunate I can't get past the decision to use exception handling to deal with non-existing keys in map. I'm of the exception-disliking school which is thankfully growing but I guess not yet universal. For me using an exception to indicate the lack of a value corresponding to a key in a map (is it really exceptional for this to happen?) is a textbook example of exception-abuse where the code is obfuscated by the non-locality of the control flow.
- enitihas 8y agoWell, for good or for bad, python does the same.
- bpicolo 8y agoTo be fair, there's utility to avoid it: check first or do a .get(). That helps you be expressive about what you think should/should not exist
- p1necone 8y agoI can definitely see the use in that. In some situations a given key not being present would actually be exceptional.
- cpeterso 8y agoYou can use dict's get() method to get back a None for missing keys instead of throwing a KeyError exception. That avoids the overhead of checking `if key in dict` or catching KeyError.
- wool_gather 8y agoAnother option, it's very easy to wrap a dict in a defaultdict: class optionaldict(defaultdict): """ A defaultdict that disregards KeyErrors and returns None for missing keys. """ def __init__(self, *original, **kwargs): super().__init__(lambda: None, *original, **kwargs)
- staticassertion 8y ago> Lily uses reference counting for memory management with garbage collection as a fallback. I'd just call this GC where it's rc + (presumably) a tracing GC. > .reject(|r| r.is_space() ) This is nice. I've always found "filter" to be a confusing name. Filter in? Filter out? 'reject' is a very clear name - if it is a space, reject it. Code looks really reasonable. I find `: {` to be a strange idiom. Why not one or the other? Seems to distinguish between single vs multiline? I guess that's reasonable. A bit noisy.
- panic 8y ago'reject:' is originally from Smalltalk, along with 'collect:' (map), 'select:' (complement of reject), 'detect:' (first matching element), and 'inject:into:' (foldl). I agree that these names are better -- they even rhyme so they're easier to remember!
- wruza 8y agoI wish we had humane keyboards with special symbolic row (or two), since this: ["+" => (|a: Integer split(" ").reject(|r| stack: List[Integer] is a shift-hell challenge to type it. Most of my unproductivity goes from being tired of mistyping or too concentrated on precise shifting. Even $150 keyboards go with classic/tkl layout at most; no chance unless going handmade.