Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend assignment function notation / make more things expressions #190

Open
Nexus6 opened this issue Oct 7, 2016 · 10 comments
Open

Extend assignment function notation / make more things expressions #190

Nexus6 opened this issue Oct 7, 2016 · 10 comments
Labels

Comments

@Nexus6
Copy link

Nexus6 commented Oct 7, 2016

I think it would be useful if "match" and "case" statements were actually expressions. For example, I'd like to be able to do things like:

def whats_this(foo) =
    case foo:
        match 0:
            #<do something>
            "Zero"
        match 1:
            #<do something else>
            "One"
    else:
        "Dunno"

assert "Zero"   == whats_this(0)
assert "One"    == whats_this(1)
assert "Dunno"  == whats_this(2)
@Nexus6
Copy link
Author

Nexus6 commented Oct 7, 2016

Also, as a precondition for this syntax, assignment functions would need to be changed to return the last expression in the chain of execution rather than the expression on the last line of the function. For example:

def new_assign(foo) = 
    if foo == 0:
        "Zero"
    elif foo == 1:
        "One"
    else:
        "Dunno"

assert "Zero"   == whats_this(0)
assert "One"    == whats_this(1)
assert "Dunno"  == whats_this(2)

I think this is desirable on its own as it simplifies the use assignment functions. There'd be no need to create a temporary variable to hold a return value that's subsequently placed on the last line of the function, and no need for creating explicit early "return" statements either.

@evhub evhub added the feature label Oct 7, 2016
@evhub evhub added this to the v1.2.1 milestone Oct 7, 2016
@evhub
Copy link
Owner

evhub commented Oct 7, 2016

@Nexus6 Yeah, I totally agree that this would be useful--it's something I've been wanting to implement since I resolved #159. Putting this issue on the v1.2.1 milestone.

@evhub evhub changed the title match/case expressions extend assignment function notation Oct 7, 2016
@evhub
Copy link
Owner

evhub commented Jan 18, 2017

As per Gitter discussion, implementation of this should involve having --strict warn about the use of normal return statements.

@evhub evhub modified the milestones: v1.2.2, v1.2.1 Feb 7, 2017
@evhub evhub modified the milestones: v1.3.0, v1.2.2 Feb 18, 2017
@evhub evhub changed the title extend assignment function notation Extend assignment function notation Jun 24, 2017
@evhub evhub modified the milestone: v1.3.0 Aug 4, 2017
@evhub evhub added this to the v1.4.0 milestone Oct 25, 2017
@evhub evhub modified the milestones: v1.5.0, v1.5.1 Mar 5, 2021
@evhub evhub removed the bounty: $50 label May 30, 2021
@evhub evhub removed this from the v1.6.0 milestone Oct 27, 2021
@evhub
Copy link
Owner

evhub commented Oct 27, 2021

I think the danger of this is that it makes assignment functions much less clear in terms of what they're returning—if you want to return something from a nested block, I think it's a good idea to just force an explicit return statement there.

@akdor1154
Copy link

This is really a subcase of everything-is-an-expression, isn't it? That's why it works in the languages people are coming from (ML-based, Rust, Haskell, ...)
If you would consider that approach for v2 it would be very consistent from a user perspective.. but would almost certainly mean throwing away py3-is-valid-coconut.

@evhub
Copy link
Owner

evhub commented Dec 9, 2021

@akdor1154 Allowing almost everything as an expression actually would likely be possible without breaking the rule that all valid Python 3 is valid Coconut, but I'm not convinced that there's actually enough of a use case for it to justify implementing it. In particular, I think statement lambdas (especially pattern-matching statement lambdas) already cover most of the use cases for something like that.

@akdor1154
Copy link

Its not so much about filling use case checkboxes, it's more (again, just from user perspective here) about consistency.

There are already special cases that work towards this: your alternative ternary operator (not needed if if is an expression), statement lambdas (would be sometimes not needed if def fn is an expression), probably more..

With everything-is-expression, the above special cases mostly become unnecessary, and the requests for other special cases (why not a match expr to go with ternary expr? Why does a statement lambda on my last line return a func, but a def func return None?) go away.

As before, the languages Coconut is inspired by largely work this way already - as a user I find the python 'actually this thing is a statement and will silently eval to None' paradigm to be jarring in Coconut's otherwise functional environments.

In practice with these other languages I haven't noticed an issue with clarity around what a deeply nested expression returns - as long as there is clear syntax to delineate the expression as a unit, which Py/Coconut's whitespace does beautifully.

@koraa
Copy link

koraa commented Jun 2, 2023

Honestly, there are a bunch of patterns where this would be useful.

Getting rid of multiple return statements reduces visual clutter and lets me focus on what I actually want to read. This is important for accessibility – personally I have to use giant fonts for vision reasons.

Having more expressions available also lends itself to a data flow oriented programming style, which is why I would like to use coconut in the first place. The way expressions vs statements are handled in coconut right now feels a bit out of place for a language that aims to facilitate a functional programming style.

I agree, that the syntax you get from allowing statements as expressions without any extra syntax elements, a bit awkward:

x = if foo == 0:
    "Zero"
elif foo == 1:
    "One"
else:
    "Dunno"

Maybe enforcing a syntax with round braces would be better:

x = (
  if foo == 0:
      "Zero"
  elif foo == 1:
      "One"
  else:
      "Dunno"
)

Or with a special keyword:

x = do (
  if foo == 0:
      "Zero"
  elif foo == 1:
      "One"
  else:
      "Dunno"
)

@ilka-schulz
Copy link

I love how if and match are expressions, not statements in Rust 🦀 and this is one of the most painful things when programming in Python (along lambdas not being closures which is solved beautifully in Coconut). I would love if this feature could be added to coconut! 🥥

@evhub evhub changed the title Extend assignment function notation Extend assignment function notation / make more things expressions Jun 2, 2023
@evhub
Copy link
Owner

evhub commented Jun 3, 2023

I'm not currently sold on this, but I certainly see the appeal. Here are what I see as the major hurdles to something like this:

  1. Many of the proposed syntaxes would create confusion with the Python constructs—which Coconut has to keep compliance with, since one of the major guarantees of Coconut is that all valid Python (on the latest Python version) should work the exact same way in Coconut. If sometimes your if statements result in the thing inside them being implicitly returned, but other times they don't, depending on whether you used it as a statement or an expression, I think that could get very confusing.
  2. This would be the only instance where line breaks and indentation matter inside of expressions. In Python, and by extension in Coconut, line breaks and indentation inside of parentheses/brackets/braces are ignored (which is the only way to get a line break in an expression). All of the proposed syntaxes for this above would break that abstraction, which I'm not super keen on breaking: Python's/Coconut's whitespace rules are currently extremely clear, and this would make them a lot more complicated.

I'm open to suggestions if anyone has ideas for this that would rectify the two issues above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants