GithubHelp home page GithubHelp logo

Comments (14)

giacomocavalieri avatar giacomocavalieri commented on August 11, 2024 1

I don't think 1 is what we should go for because it could lead to some confusion if you write this:

let assert Ok(_) = todo as "error message"

Here you can't really tell if as is part of the first assertion or the todo.

I think 3 would be the best choice if in the future we also want some kind of assert keyword to support it as well in a similar way:

// 3.
assert as "wibble" [1, 2, 3] = list.reverse([3, 2, 1])
assert as "wibble" is_empty([])
let assert as "wibble" Ok(result) = maybe_fail()

If we went with 2, that means that if we ever decide to add assert (on its own) the two ways to write it would look quite different and may be confusing:

let assert Ok(result) as "wibble" = maybe_fail()

// I don't think this looks particularly good and has the same problems as 1.
assert [1, 2, 3] = list.reverse([3, 2, 1]) as "now this is last"

// But having `assert as "wibble" [1, 2, 3] = list.reverse([3, 2, 1])`
// now would look quite different from 2. used when assigning to a variable
// here it comes after `assert` while in the other after the pattern

So that's my reasoning for preferring 3, and even if we never get an assert keyword on its own I think it still looks slightly better 😁

from gleam.

isaacharrisholt avatar isaacharrisholt commented on August 11, 2024 1

@giacomocavalieri I think I agree with you.

However, I'm assuming in your code example you meant something akin to this?

- assert as "wibble" [1, 2, 3] = list.reverse([3, 2, 1])
+ assert as "wibble" [1, 2, 3] == list.reverse([3, 2, 1])

I assume assert would just assert a boolean value in this case.

from gleam.

LilyRose2798 avatar LilyRose2798 commented on August 11, 2024 1

The as keyword as a whole is one of the more confusing keywords in Gleam in my opinion. With its use in todo as "foo" you can reasonably guess that the purpose of the string is to provide a label to the todo keyword, and with panic as "foo" you can possibly guess that the purpose of the string is to provide an error message to the panic, but the keyword as itself doesn't really do a good job at explaining anything about what the string is actually doing in either of those situations, so it's left up to the reader to deduce that via context.

With assert as "foo" (regardless of where the as actually ends up in the let assert statement), the intention of the string following the as is even less clear than the other two uses, and the as keyword in this situation does nothing to aid in the understanding of what the string might be for. Is it checking that string against something as part of the assertion? Or doing something else with the string? For new users of the language, I think this will be pretty confusing to read.

The issue that needs to be solved is being able to provide extra data to certain keywords, preferably in a way that makes it clear what the data being provided is (like with a labelled function arg), but without having the syntax be confused with a function call.

As a potential solution to this issue (or at least what I believe is an issue), I propose the following alternative to the as syntax, that can replace the current usage of as in its current use with todo, panic and be used in the future with assert:

todo #label="foo"
panic #error_message="foo"
assert #error_message="foo"

// whitespace should be supported everywhere except for after # to avoid parsing
// confusion with tuples or user confusion with comment syntax in other languages
todo #label = "foo"

// if a keyword supports more than one data item, they can be provided like so
todo #label="foo" #description="more detailed info"

The syntax is inspired by url query params (which helps to reinforce that they're optional attributes, not required ones). The language server should ideally show the available attributes that can be provided when hovering over a keyword, similar to a function signature (though distinct enough to avoid confusion).

I believe the only place the # symbol is used currently is in tuples, and for those it is required to be followed by either whitespace or a (, whereas in this situation it will always be followed by a name/identifier (which cannot include ( or whitespace), so determining which it is in the parser should not be too difficult I imagine.

It might also be worth considering allowing this syntax to occur anywhere on the same line as a supported keyword for the purposes of keeping the main body of the line clean, such as with the following:

let assert Ok(foo) = returns_result() #error_message="got an Error instead of Ok"

It would basically act as a comment, except it would be passed as context to any keywords on that line. Any attributes that don't apply to a particular keyword can just be discarded when passed to it, which allows for lines containing multiple keywords to still receive their respective data:

let assert Ok(foo) = todo #error_message="got an Error instead of Ok" #label="add code that returns a Result"

Interested to know what others think of this suggestion, or if anyone has any other suggestions for the syntax of something like this.

from gleam.

giacomocavalieri avatar giacomocavalieri commented on August 11, 2024

I've never seen as as confusing, it's really interesting to hear other's opinions about it!

Personally, I don't think that the labels make it any clearer than as: moving the error message at the end of the line away from the assert doesn't make it clearer, with as next to assert I immediately can tell that that's the assertion's error message and I don't have to skim through to the end of the line to see if it has any extra label attached

from gleam.

LilyRose2798 avatar LilyRose2798 commented on August 11, 2024

If keeping the label close to the source of the keyword is a desired property, then only allowing the #attribute right after the keyword could maybe be an option?

let assert#error_message="failed to match" Ok(foo) = returns_error()

from gleam.

isaacharrisholt avatar isaacharrisholt commented on August 11, 2024

I also don't see as as a confusing thing. Like any keyword in any language, you have to learn its meaning, but once you've got it, it's fairly simple.

Also moving away from as to an attribute-based system like you've described would be a breaking change, which would need a whole new version number. The way to prevent that would be to keep as around, and I think having two bits of syntax for the same thing would arguably be even more confusing.

from gleam.

LilyRose2798 avatar LilyRose2798 commented on August 11, 2024

I think as is ok-ish in its current usage for todo and panic, but assert as is getting to the point where it's becoming confusing to read in my opinion, and if more keywords are ever added, as is unlikely to really make sense from a readability standpoint for those either.
I understand the viewpoint of not wanting to introduce any more breaking changes though, so I'm not really sure how to improve the situation if anything breaking is off the table.

from gleam.

isaacharrisholt avatar isaacharrisholt commented on August 11, 2024

It's not really any different to languages that do assert predicate, "failure message", though I'd argue that's more confusing because in those languages (e.g. Python), x, y could be a tuple.

from gleam.

lpil avatar lpil commented on August 11, 2024

It has to be as, that is the established syntax for adding a message to a panic. We will not have a breaking change Ζ’or that so there's no point in discussing alternatives.

Hayleigh has pointed out on discord that let assert Ok(result) as "wibble" = maybe_fail() is already valid syntax so we cannot use it here. This is unfortunate.

from gleam.

sobolevn avatar sobolevn commented on August 11, 2024

I am working on this right now :)

The main change would be:

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AssertAssignment<ExpressionT> {
    pub location: SrcSpan,
    pub message: Option<Box<ExpressionT>>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Assignment<TypeT, ExpressionT> {
    pub location: SrcSpan,
    pub value: Box<ExpressionT>,
    pub pattern: Pattern<TypeT>,
    pub assert: Option<Box<AssertAssignment<ExpressionT>>>,
    pub annotation: Option<TypeAst>,
}

from gleam.

giacomocavalieri avatar giacomocavalieri commented on August 11, 2024

Implementation won't be too complex but we haven't landed on a design yet, I would wait until we decide what this should look like or the PR might not get merged as of now

from gleam.

sobolevn avatar sobolevn commented on August 11, 2024

I will send a prototype with the 3. option. Since 2. is already doing something else.
And 1. looks very different from the current todo as "" and panic as "" cases.

It can always be closed if some other option is a better fit. For me this is just a good way to learn the internals of this compiler :)

from gleam.

lpil avatar lpil commented on August 11, 2024

How would it work with the upcoming assert x != y syntax? How would as work there?

from gleam.

sobolevn avatar sobolevn commented on August 11, 2024

@lpil sorry, I couldn't find the new assert spec anywhere, so I might be missing something. Generally assert as "x is not equal to y" x != y seems fine to me. In this case it would use this as a base message, while it also should show what x and y was in the error's context.

from gleam.

Related Issues (20)

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.