Code Monkey home page Code Monkey logo

Comments (12)

spy16 avatar spy16 commented on June 4, 2024 1

However [].bar is hard because there is no [] symbol anywhere in the namespace.

Not quite. Issue is that the moment reader sees [ it drops into the logic that parses a vector and stays there until it reaches a matching ] and when it does, it's considered end of one form. Following . will not be considered as part of this. Instead another symbol .Cons will be emitted . Instead of having a form that expresses [].Cons you'll end up with 2 forms a list [] and a symbol .Cons ..

But I think it's best not to worry about this now at all. Gain in simplicity is bigger compared the loss in this minor detail.

from sabre.

lthibault avatar lthibault commented on June 4, 2024 1

👌For points 1 & 2.

And i think it would be nicer to allow kebab case naming for member access.

👍

I am considering may be both foo.GetTheName andd foo.get-the-name should work. Let me know what you think..

I'm very much in favor of this. Kebab-case is certainly convenient, but forcing case-conversion adds cognitive overhead for users, and may at times be more confusing than the native names.

Also, I am thinking no dots allowed in symbols similar to all other languages.

Strongly agree. Dots have special meaning. Disallowing their use in symbols helps signal intent. Furthermore, we should avoid letting people abuse dots in weird ways in case we need to make changes to field lookup semantics in the future.

Overall: 👍

from sabre.

lthibault avatar lthibault commented on June 4, 2024

I've been thinking of this on my end as well, and agree that such functionality should be exposed.

I saw it as a (.method-or-field target) form, however, implemented by a ReaderMacro. I'm not opposed to the . function approach, but I'm curious why you prefer it?

In my mind, a Go-flavored lisp should aspire to the same minimalism that one finds in Go. One minor annoyance I have with various lisps (including Clojure) is the sheer number of exported symbols in the default namespace. Clojure's core namespace has over 200 exported functions, for instance! 🤢

One of my aspirations for my own project is to keep the language spec very small. In so doing, I hope to attain the same kind of simplicity as one finds in Go, and in order to achieve this, I would argue that we should build a lisp engine that reduces the number of functions that need to be implemented, rather than pushing functionality out to functions. A powerful introspection system for native Go structures seems like an opportunity to do just that.

I'm not sure what else we could be doing to move in this direction, but I'm interested in any thoughts you might have.

Returning to the point at hand, my gut tells me this should not be a function, but I'm open to being wrong! 😄

Addendum: regarding the point about Go-style simplicity above, I think this also touches upon an important marketing consideration for Slang. If we want this library to take off, it's important that we differentiate it from all the other "make a lisp" libraries on GitHub. A heavy emphasis on making simple (i.e.: small, feature-conservative) lisps is a very interesting niche in this respect. We would benefit from being unique as well as being aligned with the philosophy of the host language (Go).

from sabre.

spy16 avatar spy16 commented on June 4, 2024

I have with various lisps (including Clojure) is the sheer number of exported symbols in the default namespace

Same here. That's why i took this decision in fact. My idea was that a minimal scope would export only few selected functions like ., def, fn* etc. and things like cons, conj, seq? etc. would be built using pure lisp and are not included by default.

I'm not opposed to the . function approach, but I'm curious why you prefer it?

To be honest, I am not totally happy with it either, i am definitely open for suggestions. Only reason I picked this was to ensure there is no special handling of things. For example if I picked (.member target) approach, everytime a list is evaluated, the evaluation logic would have to check if the first item in the list starts with a . ..

It's not possible to do this with a ReaderMacro in a generic way as it stands, and here's why: ReaderMacro is completely decoupled from a Scope, so it has no knowledge of what target values are available. Even if we introduce a new member access expression/form that reader emits, we will also have to provide a way to construct this expr without reader (lisp principle: code and data are not different)..

I can think of following alternatives here:

  1. Make Reader depend on a Scope and make it emit the member being accessed as the value from the reader.
  2. Enable (target.member args...) kind of access which would make it simpler (but need to handle ambiguity when a symbol itself has a . in it.
  3. Enable ((.member target) args...) approach

I think approach 2 would be the simplest to use in most cases.. But the problem is, we will not be able to use it against inlined values.. i.e., ((.Cons []) 1) can be done with approach 3 for example, but in approach 1 & 2 it would be ([].Cons 1) which is ambiguous for parsing..

A powerful introspection system for native Go structures seems like an opportunity to do just that.

This is what i was going for too.

I was thinking of simplicity in terms of design of Sabre as library itself: Provide a bare-bones environment which can be built upon.

from sabre.

lthibault avatar lthibault commented on June 4, 2024

Enable target.member kind of access which would make it simpler, but we will lose capability to have nested namespaces like sabre.core.math (which i think is not necessary, let me know what you think)...

An alternative would be to take Python's approach and model namespace lookups as regular object lookups. Imagine you have a namespace with a foo.bar symbol that maps to a type t struct { Baz int }. The expression foo.bar.Baz could be supported by the following algorithm:

  1. Look for a common substring in the namespace. We find that the namespace contains foo.bar
  2. Get the corresponding object from the namespace. Call it o.
  3. Trim the common substring foo.bar off of the fully-qualified lookup symbol, foo.bar.Baz. The result is Baz.
  4. Repeat steps 1-3 using o instead of the namespace, until the the algorithm terminates.

Honestly, I really like this approach:

  • It removes the need to support two distinct separators (/ and .) in order to resolve symbols.
  • It makes for a natural hierarchical grouping of symbols.
  • It makes lookup conventions identical for namespaces and regular objects, reducing cognitive overhead.

This is one of the things I think Python does extremely well. This kind of encapsulation is (IMHO) the only real upside to modeling data as objects. Provided we don't encourage stateful objects, I see no downsides.

This is what i am going for too. In fact now that member access is allowed, i was considering to implement things like cons, conj etc. through this.

+1 for this.

I was thinking of simplicity in terms of design of Sabre as library itself: Provide a bare-bones environment which can be built upon.

Yes, I think this is also very important. My suggestion was more of a supplement than an alternative. Point is: I'm favor of strategically adding a little bit of complexity in a select few places in order to encourage the design of simple languages.

from sabre.

spy16 avatar spy16 commented on June 4, 2024

Enable (target.member args...) kind of access which would make it simpler (but need to handle ambiguity when a symbol itself has a . in it.

Actually, forgot to correct this part. This can be handled like you said and i really like this too.. It's how Go does it pkg.Symbol.Member.SubMember etc. it's how Python does it.. But one problem i see is w.r.t., member access on literal values.. for example, to access Cons method of a vector/list literals.. Like ([].Cons 1) which would be hard to parse.. This is not a major problem though if we think it's okay to add some additional boilerplate in case of literals.. i.e., (let [empty-vec []] (empty-vec.Cons 1))..

What do you think ?

from sabre.

lthibault avatar lthibault commented on June 4, 2024

This can be handled like you said and i really like this too..

Awesome - then consider me onboard 😃

But one problem i see is w.r.t., member access on literal values..

Just to make sure I understand, the difficulty is exclusively at the parsing level because it involves some form of lookback / context? For example, foo.bar is easy to parse because foo can be located in the namespace. However [].bar is hard because there is no [] symbol anywhere in the namespace.

Assuming I've understood the issue, I'm 100% onboard with your proposed mitigation strategy (which is basically to not worry it for now). It would nevertheless be good to handle this more elegantly in the mid-to-long term. Perhaps we can open an issue and get back to it later?

from sabre.

lthibault avatar lthibault commented on June 4, 2024

Ah yes, of course! Ok, makes sense.

But I think it's best not to worry about this now at all. Gain in simplicity is bigger compared the loss in this minor detail.

Totally agree.

from sabre.

spy16 avatar spy16 commented on June 4, 2024

Cool. I'll try to get this done when I get sometime. Thanks for bringing this up.. I got caught up in doing things similar to Clojure I guess.. 😅

from sabre.

lthibault avatar lthibault commented on June 4, 2024

Thanks for bringing this up.. I got caught up in doing things similar to Clojure I guess.. 😅

No sweat - I'm happy to be part of the design process :)

from sabre.

spy16 avatar spy16 commented on June 4, 2024

Just to put the above discussion into final points:

  1. No special treatment for namespaces. They are just objects bound in the scope.
  2. Simply split the fully qualified symbol using . as the delimiter and do recursive lookups until termination.

And i think it would be nicer to allow kebab case naming for member access. (i.e., if the method of a type Foo in Go is named GetTheName, from Sabre it would be better to have foo.get-the-name kind of access)... I am considering may be both foo.GetTheName andd foo.get-the-name should work. Let me know what you think..

Also, I am thinking no dots allowed in symbols similar to all other languages. Clojure allows this but in a weird & useless way: (def hello.world 10) works and creates a binding, but when you try to use the symbol hello.world somewhere it just throws ClassNotFoundException.. I can't really think of a use-case where using . in names can make it better/readable. But allowing it can be confusing (For example when i type foo.bar.baz, it's not really clear if it is resolving baz of foo.bar or is foo.bar.baz itself is a value?)..

from sabre.

spy16 avatar spy16 commented on June 4, 2024

This has been implemented. I have not done support for kebab case yet. For now going to keep only native names.

from sabre.

Related Issues (17)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.