Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

comprehensions beginning with if clause #3975

Closed
CeylonMigrationBot opened this issue Dec 4, 2013 · 32 comments
Closed

comprehensions beginning with if clause #3975

CeylonMigrationBot opened this issue Dec 4, 2013 · 32 comments

Comments

@CeylonMigrationBot
Copy link

[@gavinking] Currently, a comprehension must begin with for. For #3913 we should relax this restriction, and allow a comprehension to begin with if. Then, for example:

{ if (exists x) x }

Evaluates to {x} if x exists, or to {} otherwise.

Likewise:

 [ if (!string.empty) string ]

Evaluates to [string] if string is not empty, or to [] otherwise.

[Migrated from ceylon/ceylon-spec#869]
[Closed at 2014-01-28 11:57:01]

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Should we also allow expressionComprehensionClauses at the start? That would mean that

{String+} asSequence = { "element" };

would be a comprehension instead of an enumeration with a one-long sequencedArgument.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister]

Should we also allow expressionComprehensionClauses at the start?

God no. { element } is something completely different than { } and { element1, element2 }? Hell naw.

I’ll try to implement this; let’s see how far I get. I think I’ve got the grammar part, now I have to fix the Visitors.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Okay, I have something. I get 6 failures and 3 errors in the ceylon-compiler tests, but I also get these in a clean working tree – is my setup messed up or is this correct?

Also, I’m suspicious. That was way too easy. Let’s try if it works...

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Haha, yeah. It was too easy. For some reason I thought that if it compiles, then the rest happens automagically...

I see two ways of making comprehensions with leading if work (EDIT: for the Java platform. haven’t looked at JS yet). First of all, here’s a brief overview on how comprehensions currently work as far as I understand it, in case you want a refresher.

  • the regular way would be to generate $next$0() for initial if clauses (and then $iterator$1() for the following for clause, which is currently just set in the "constructor"), and teach $next$X() and $iterator$Y() that there’s not always a previous iterator.
  • the hacky way would be to put the initial if clause(s) outside the anonymous AbstractIterable, and just return empty if the conditions don’t apply.

The main difference between these is that in the hacky way, the conditions are evaluated when the Iterable is created, while in the regular way they are evaluated when the Iterable is first evaluated. That’s a big difference if the condition has side effects, and I think that the semantics of the regular way make more sense. WDYT?

Also, in case someone else wants to work for this, here are my grammar changes, and I’m pretty confident that these are sufficient.

@CeylonMigrationBot
Copy link
Author

[@gavinking] However you implemented, the condition needs to be evaluated lazily, each time the comprehension is evaluated. (Comprehensions can be reevaluated.)

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Progress report: I think I have implemented all necessary changes in the ExpressionTransformer (I went with the regular way), and I’m not sure where the ExpressionVisitor needs more work. Unfortunately, I currently get an NPE about 75 stackframes down a horrifying com.sun.javac... rabbit hole when compiling { if (exists x) x }, and I have no idea how to debug that. I need some sleep first.

If anyone’s interested or wants to try and fix the error, here’s my current changes: https://gist.github.com/lucaswerkmeister/8466797 (copy, then xclip -o | git apply)

@CeylonMigrationBot
Copy link
Author

[@FroMage] Look at the generated .src, in theory you see it displayed before it crashes.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] I see it, looks as intended, compiles fine when I put it in its own file (and fix the .type.names).

----- Ursprüngliche Nachricht -----
Von: "Stéphane Épardaud" notifications@github.com
Gesendet: ‎17.‎01.‎2014 09:42
An: "ceylon/ceylon-spec" ceylon-spec@noreply.github.com
Cc: "Lucas Werkmeister" mail@lucaswerkmeister.de
Betreff: Re: [ceylon-spec] comprehensions beginning with if clause (#3975)

Look at the generated .src, in theory you see it displayed before it crashes.

Reply to this email directly or view it on GitHub.

@CeylonMigrationBot
Copy link
Author

[@FroMage] Show me the .src and stack trace?

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] When I'm home, ca. 1.5h

----- Ursprüngliche Nachricht -----
Von: "Stéphane Épardaud" notifications@github.com
Gesendet: ‎17.‎01.‎2014 10:19
An: "ceylon/ceylon-spec" ceylon-spec@noreply.github.com
Cc: "Lucas Werkmeister" mail@lucaswerkmeister.de
Betreff: Re: [ceylon-spec] comprehensions beginning with if clause (#3975)

Show me the .src and stack trace?

Reply to this email directly or view it on GitHub.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Okay. Took a little longer that expected, because I fixed some other bugs first. This isn’t the same exception as yesterday night, but it’s close enough, I think.

  • for if
  • if for
  • the changes to ceylon-spec, ceylon-compiler and ceylon-js, in case you want to test it yourself

@CeylonMigrationBot
Copy link
Author

[@FroMage] IMO it's the anonymous constructor block that is the issue. Looks like it was not declared properly in the AST. Try removing it.

@CeylonMigrationBot
Copy link
Author

[@FroMage] No that's crazy, this is already used now. Looks like the class symbol has a package kind. This is just crazy.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] I agree it’s crazy, because I get a different exception when I’m debugging from Eclipse than when I’m running it from the command line...

But you’re actually right; at least when I’m debugging from Eclipse, javac gets an NPE because the stats (statements) of the anonymous contructor are empty (null element).

I’ll fix that (initialize boolean $next$0$exhausted$ to false), and then see what happens.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] correction: not empty, the ExpressionTransformer has an initIterator statement, and if transformForClause doesn’t set that, it actually adds a null statement to the constructor.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] And it compiles!! AssertionError in the test case of course. Just a few more seconds...

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Dammit! It works from the IDE and crashes with still the same error (kind 31 etc.) on the command line.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Kind 31 is the ERR kind, by the way. The only place where it’s set that I could find is in Type.java, line 1309 – the ErrorType. So javac recognizes some error somewhere, but decides to not tell me about it, crashing later instead, when any trace of the error is long wiped from the stacktrace. Wonderful.

I’m visiting my parents over the weekend, so unfortunately I won’t be able to work on this until sunday evening. If you want to try things out, you can see my two commits referenced above; that’s all I have.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Actually... I was just able to compile and run the following code on my netbook:

void run() {
    {String*} strings = { if ("hi".contains("h")) "Hello, World!" };
    print(strings.first);
}

I’ll have to check why. Weird architecture bug (32/64-bit) or not caused by me and fixed in the meantime?

(Interim report: typechecker and java backend apparently done, javascript backend todo.)

@CeylonMigrationBot
Copy link
Author

[@gavinking] Sounds good!

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Alright, I think I have some implementation for the Javascript backend. However, I currently get:

TypeError: Property 'next' of object ceylon.language::ComprehensionIterator@1 is not a function

Now that I’ve committed my changes, I can go back to master and check if that’s really my error. (Probably, but you never know!)

Also, I got the error (kind 31) on the Java backend again, but then it suddenly vanished. Maybe ceylon/ceylon-compiler@024c4b8 fixed it?

(Interim report: typechecker and java backend apparently done, javascript backend needs more testing and bugfixing.)

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Alright, I found and fixed the remaining known bug in the JS backend (spoiler: it was a really stupid one). I’ll write some more tests now, and then I think it’s time for a pull request!

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Phew! Pull requests opened. (Example code over at #4014.)

@CeylonMigrationBot
Copy link
Author

[@gavinking] Awesome! Thanks!

@CeylonMigrationBot
Copy link
Author

[@FroMage] Thanks, we'll take a look ASAP, and merge it. FTR we're going to try to move to a single repo real soon so you don't have to go through that pain again for pull requests.

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Cool, sounds good!

FTR, I already started rebasing the branches locally to resolve conflicts ASAP (since this used to be scheduled for 1.2). No conflicts so far though.

@CeylonMigrationBot
Copy link
Author

[@gavinking]
@FroMage

Thanks, we'll take a look ASAP, and merge it

ETA? I have reviewed the typechecker changes, which look good, and am ready to push them.

@CeylonMigrationBot
Copy link
Author

[@gavinking] I have pushed the typechecker changes. Changes to ceylon-compiler and ceylon-js still need to be pushed.

@CeylonMigrationBot
Copy link
Author

[@gavinking] All done. Thanks, @lucaswerkmeister, great work!

@CeylonMigrationBot
Copy link
Author

[@FroMage] I have reviewed the jvm compiler changes and they seem very good, congrats! I have added some tests though, as I felt there were some cases missing.

Do you mind adding runtime tests for this in the language module? We've had lots of bugs in comprehensions at runtime in the past and we absolutely need to test this, we can't rely just on how the compilation looks ;)

Thanks!

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] @chochos already bugged me about runtime tests :) he suggested a few, I added these and a few more in ceylon/ceylon.language@f8ef15c, ceylon/ceylon.language@4864b49.

@CeylonMigrationBot
Copy link
Author

[@FroMage] OK if you added them already then sorry, it's great :)

@CeylonMigrationBot CeylonMigrationBot added this to the 1.1 milestone Nov 14, 2015
quintesse pushed a commit that referenced this issue Nov 14, 2015
quintesse pushed a commit that referenced this issue Nov 14, 2015
Suggested by @chochos [1]. I added another test to verify that
conditions after a false condition are not evaluated:
    if (false) if (functionWithSideEffects()) value
should not have side effects.

[1]
lucaswerkmeister/ceylon.language@f8ef15c#commitcomment-5126747
gavinking added a commit that referenced this issue Nov 14, 2015
gavinking pushed a commit that referenced this issue Nov 14, 2015
* `(if)+ expression` did not have a "tail", i. e., did not return if the
  condition was false
* `(if)+ (for) (if|for)* expression` wrote the "tail" before closing the
  "if"’s braces: a) double return inside the if, b) missing return
  outside the if

part of #3975
gavinking pushed a commit that referenced this issue Nov 14, 2015
(that is, comprehensions without "for" clauses.)

(Part of #3975.)
gavinking pushed a commit that referenced this issue Nov 14, 2015
(that is, comprehensions without a "for" clause)

The comprehension would return the result infinitely instead of only
once.

Still part of #3975.
quintesse pushed a commit that referenced this issue Nov 14, 2015
This also significantly simplifies the $next$0() method – see the test
case.

CC #3975
gavinking pushed a commit that referenced this issue Nov 14, 2015
This also significantly simplifies the $next$0() method – see the test
case.

CC #3975
gavinking pushed a commit that referenced this issue Nov 14, 2015
Introduces the new abstract class InitialComprehensionClause as
superclass of IfComprehensionClause and ForComprehensionClause to the
tree.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants