Skip to content

Conversation

b-studios
Copy link
Collaborator

Constructors and operations are now defined in a namespace, named after the type.

For instance:

type TrafficLight { Red(); Green(); Yellow() }

defines the constructor TrafficLight::Red, but also imports it as Red. The same holds for operations, which can now (in principle) be disambiguated like cap.Nondet::flip().

As a drive-by, I simplify the way operations are looked up and drop the unused effect on Do, which was in preparation for do Nondet.flip(), which now is do Nondet::flip().

@b-studios b-studios requested a review from timsueberkrueb July 23, 2025 13:22
@b-studios
Copy link
Collaborator Author

b-studios commented Jul 23, 2025

@timsueberkrueb there is a LSP Server test failing:

==> X effekt.LSPTests.Server publishes term names in the correct order  0.555s munit.ComparisonFailException: LSPTests.scala:1782
1781:
1782:      assertEquals(outerBindings.length, 3)
1783:      assertEquals(outerBindings(0).name, "e1")
values are not the same
=> Obtained
5
=> Diff (- obtained, + expected)
-5
+3

Can I just update the number or do we want the change the behavior in the server?

@b-studios
Copy link
Collaborator Author

b-studios commented Jul 23, 2025

@timsueberkrueb Could you double check w.r.t. to the "outline" and holes panel? In particular, I am afraid that operations might now show up twice (once in the namespace and once outside).

Comment on lines +13 to +16
def consume(b: Bars) = b match {
case Foo(Foo::Bar()) => 1
case Boo(Boo::Bar()) => 2
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here you can see that we now can also disambiguate equally named constructors in patterns.

@timsueberkrueb
Copy link
Contributor

@timsueberkrueb Could you double check w.r.t. to the "outline" and holes panel? In particular, I am afraid that operations might now show up twice (once in the namespace and once outside).

Yes, they do indeed occur twice now.

image

@b-studios
Copy link
Collaborator Author

I discussed this with @timsueberkrueb: Ideally, the semantics of

type Color { Red(); Green() }

is

type Color { Color::Red(); Color::Green() }
import Color::*

so the unprefixed constructors (and operations) should be listed as imports, not bindings.

@b-studios
Copy link
Collaborator Author

b-studios commented Jul 24, 2025

I implemented it, but it isn't that simple. Assume two files with the import semantics:

// color.effekt
type Color { Color::Red(); Color::Green() }
import Color::*

and

// colorpicker.effekt
import color
def chooseColor(): Color = Red()
                           ^^^^^
         Cannot find a function named `Red`.

then the "generated" import Color::* will only be applied in the scope of color.effekt, but not in colorpicker.effekt.

@b-studios
Copy link
Collaborator Author

So, backtracking, the semantics implemented previously (and which I plan to go with for now) is

type Color { Color::Red(); Color::Green() }
export Color::*

Since Red and Color::Red refer to the same symbol we can later choose which one to show. Maybe this is easier to solve once we reconsidered qualified names.

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