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

feat: Various small improvements to Python code generation #2081

Merged
merged 12 commits into from
May 4, 2022

Conversation

fabiomadge
Copy link
Collaborator

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

@fabiomadge fabiomadge marked this pull request as draft April 29, 2022 23:09
@fabiomadge fabiomadge changed the title Feat: Various small improvements to Python code generation feat: Various small improvements to Python code generation Apr 29, 2022
@fabiomadge fabiomadge marked this pull request as ready for review May 2, 2022 22:10
@fabiomadge fabiomadge self-assigned this May 3, 2022
Copy link
Member

@robin-aws robin-aws left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still thinking through the changes necessary to support let expressions, but in the meantime here are a couple of comments.

@property
def Elements(self):
return self

@property
def UniqueElements(self):
return Seq(set(self))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be set(self) couldn't it? It just has to be something compatible with whatever CreateForeachLoop emits (i.e. anything iterable).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really matter here, but I think it's the type dafny assumes.

Copy link
Member

@robin-aws robin-aws May 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UniqueElements is just something that needs to be called in the target language, it doesn't have to produce a "Dafny value" at this level of abstraction. Just set(self) will work because it will only be used to compile something like this:

var mySet := set x | x in mySeq

To something like this in Python:

mySet = _dafny.Set()
for x in mySeq.UniqueElements:  // <- produced by PythonCompiler.CreateForEachLoop
  mySet.add(x)

What you've got is correct too, since _dafny.Seq is also iterable, I'm just trying to save us an extra object creation. :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will undoubtedly work for python(see it doesn’t matter here) and given that this is only used immediately in comprehensions, like you described, it doesn’t matter in general. That being said, I do like the cleaner interface of returning a sequence, but your overhead argument is compelling, so I’ll adopt it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! It's purely an optimization, and normally I wouldn't prioritize it at this stage, but this is a really easy one. :)

@@ -158,3 +179,12 @@ def euclidian_modulus(a, b):
@dataclass
class HaltException(Exception):
message: str

def quantifier(vals, frall, pred):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frall - intentional to avoid name conflict or typo? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's what Java, C#, and JS call it, but I don't deeply care.

@@ -39,10 +39,31 @@ def _tail_call():
raise TailCall()

class Seq(list):
def __init__(self, __iterable = None, isStr = False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testing coverage for this is implicitly in Hello.dfy, I assume, which only worked before because we were just emitting a base Python string?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we weren't doing anything with the strings other than passing them around, so it was fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record this version is definitely incomplete, since any value of type seq<char> is a string according to Dafny, even if it isn't a literal. Here's a test case we should add for the next step:

method Main() {
  var manualString := ['H', 'e', 'l', 'l', 'o'];
  print manualString;  // Still prints "Hello" and not "['H', 'e', 'l', 'l', 'o']"
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll try to add it in this one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, let's leave it for the next step. We'll need a more general implementation of a type descriptor anyway (for dynamic type checks like is), better to do that properly in a separate PR.

Comment on lines +4884 to +4887
if (su != Substituter.EMPTY && TargetLambdasRestrictedToExpressions) {
wStmts = wr.Fork();
wr = EmitReturnExpr(wr);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting for the record that as I'm better appreciating our solution so far for TargetLambdasRestrictedToExpressions, I definitely see more speed bumps down the road for edge cases we don't handle correctly, because we're not doing this "post hoc clean up" for every possible method call that might need it. I won't likely see an immediate alternative and don't want to block this proven progress, but I do want to revisit before we go too much further.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those changes are unlikely to be comprehensive, but I was hesitant to introduce additional untested changes.

Comment on lines +51 to +52
protected override string True { get => "True"; }
protected override string False { get => "False"; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do compilers do April fools' day?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh if we're going to do that, we should do it in the verifier instead. :)

Copy link
Member

@robin-aws robin-aws left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on the condition that the next PR adds a beefy comment on TargetLambdasRestrictedToExpressions about how we're using wStmts and why we have to conditionally add return statements in the SinglePassCompiler superclass. :)

@robin-aws robin-aws merged commit 356e8f0 into dafny-lang:master May 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants