Sophia: feedback & questions from Henning Diedrich

I had some discussion lately with @brianiac.5, the inventor of Lexon and one of the judges of the past DAO-FI Fusion Hackathon and he provided me some feedback & questions that I want to share here and get answered/commented by @radrow.chain, @ghallakaeternity.chain or @hanssv.chain :slight_smile:

Question 1 (Henning)
As discussed in the community live event of the hackathon: is it true that you can’t dynamically hook in any functionality afterewards in any way? A la Solidity delegatecall()?

Question 2 (Henning)
Have you made the extension that you can write state.a = b instead of put(state{a = b})?

Comment (Henning)
In general I also think that some people give up with None and Some(_). Would be great if you could find “Sugar” for the necessary switches for assignment and readout, so that you don’t have to use option functions (e.g. Option.force) everywhere.

I have specially developed an option that you can create ‘unsafe’ code, but it is much more readable. Isn’t it supposed to be one of FP’s strengths, that it’s WELL readable?

The assignment via put(), combined with Option.force makes the code so unreadable that it again becomes harder to find errors, maybe “just” even harder to understand it and keep track of the business logic behind it. Little effort is needed for this, I think, as allowing “Sugar” to break up the pure doctrine and also make it more inviting to newcomers. But also purely practical, to make it more readable.

Specifically, I mean things like:

switch(state.x)
   None => put(state{x = y})
   Some(_) => put(state{x = x + Option.force(y)})

Alternatively probably:

put(state{Option.default(x, 0) + Option.default(y, 0)

Where the simple point is to please make x += y.

Comment (Henning)
Ref: Syntax - æternity Sophia Language

I think a sophisticated language like Sophia should be documented a bit more extensively. I’m probably not alone in not watching videos and tutorials. I like to have the basics dense. But this is a little too dense for me. The content should be presented in a slightly less encapsulated way.

Feature request (Henning)
It would be great if the compiler allows block comments, example:

Message(/* from */ indexed address, /* to */ indexed address, string)


Comment (Marco)
Henning also mentioned that he in general loves Sophia, just to make that one clear :smiley:

This is just some feedback I wanted to share here in the forum to discuss.

3 Likes

Thanks for the feedback, much appreciated! These are my thoughts/answers…

Q1. No, this is not possible, and it is by design. There is no equivalent to delegatecall nor to fallback that exists in other ecosystems. In Sophia/FATE, each contract is master of its own state.

Q2. I have seen the suggestion before, and I personally don’t like it. There has never been any plans (as far as I know) to implement this. It is a feature of Sophia that state updates are very explicit - I don’t see any reason to change this. (Note: In general I like short code (and find that more readable), but this isn’t exactly a general purpose programming language. For smart contracts explicit state updates and the likes makes good sense.)

Arithmetics on option(int) is an interesting example, unfortunately the snippets of code are somewhat contradictory. The switch one says that None "+" None is None the second one says it is 0 - also what is the type of state.x? Is it int or option(int). Overloading + or += like that will most likely not improve readability :see_no_evil:. In this case I would suggest implementing add_option and just do
put(state{x = add_option(state.x, y)})

Fair point about the documentation! Though, perhaps I wouldn’t call Sophia particularily sophisticated - it is a really simple language for a pretty specific purpose!

Block comments could certainly be added - being an Erlang programmer originally I’m not desperate to have them… But it is probably a good first problem to tackle for a new contributor!

4 Likes

Q1: delegatecall looks quite dirty to me, especially the way it works in Solidity/evm. What I could lean to instead is namespace-deploy for stateless functions as a vm feature. This would allow sharing parts of code and could drastically reduce code duplication on chain. Lack of state there is a must, we don’t want to risk any incompatibilities.

Q2: To be honest my preference would be to move the exactly opposite way and get rid of put entirely. State changes pollute semantics and introduce many corner cases. I like how Elm does it by going fully reactive and moving all external interactions away to events. This would be a drastic paradigm shift though.

The in-place record update syntax may look enticing and obvious in a sense, but it contributes to embracing imperative programming. We don’t really want that. However, I am aware how painful it is to update nested records - currently a good solution is to split the process to intermediate steps by constructing the final value with lets and using one put at the end. It’s annoying, but at least makes things explicit.

What I would rather do in the current situation is to think how we could improve pure updates of records. There is already nice syntax for flat updates, but maybe we could think about something for reaching deeper. I would keep the put though.

Comment/option:

The whole point of option is to consider a case where the value may not exist. If you are sure you are going to call Option.force, then why use option in the first place? Yes, there are built-in functions that return an option, so you don’t always have control over it, but that is for a reason. Some operations just “return nothing” and your code has to deal with that.

The proposal smells a lot like NULL to me, and that is an absolute cancer in literally every language that features it. If the “business logic” relies on implicit assumptions (eg that this int is in fact not an int but either an int or a None), then it’s even less readable. And by “readable” I don’t mean clarity of what the program is supposed to do, but what it actually does.

Regarding the += example:

  • If it is clear that state.x is a Some at this point, it is worth considering why it is an option in the first place. Well, it may be the case that /in general it may happen to be None, but in this particular line we know it’s a Some/. But then:
    • If it is because it has been certainly set as a Some in the very same call, then it’s a better idea to construct the final value beforehand and put it to the state as Some when it’s fully ready. Ideally you would have max one put per state field per call.
    • If it’s because you assume that this happened after some other call which had set it to Some, then in fact you don’t know it’s a Some and it’s good that Sophia forces you to consider it, or at least explicitly admit that you don’t care. Alternatively you can use Option.force_msg at the beginning of the entrypoint to extract the value and then work with it as an unpacked int.
  • If it is not clear that state.x is a Some then refer to above.

Also, there is Option.map which you may find useful for doing “x+=y” safely:

put(state{ 
  x @ xo = Option.map(xo, (v) => v+y) 
}) 

We want Sophia to be primarily safe, and after that convenient. We would rather keep it a bit annoying than surprising or ambiguous. As Hans pointed out, it’s not a general-purpose language. Personally I am a fan of rich syntaxes and moving repetitive abstractions away, but here I stand for predictability, stability and explicitness. In fact, many inconveniences can be eliminated by sticking to the functional paradigm. Sophia is not and shall never be imperative, thus it should not be disappointing that using it like an imperative language comes out clunky.

Commeny/docs

100% agree and we are planning to fix it. We will add normal docstrings and feature to generate documentation. We will also revisit the language documentation. For that it would be super helpful to know what exactly is considered unclear - it is mostly all clear to us, which makes it hard to keep it informative for newcomers.

Final

Thank you a lot for the feedback. Knowing what bothers users is always very useful and so appreciated, even when we don’t agree on what exact solutions are to be taken. We are working now on a major refactor and we hope to improve the experience by a lot.

4 Likes