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

Next version! #732

Draft
wants to merge 134 commits into
base: master
Choose a base branch
from
Draft

Next version! #732

wants to merge 134 commits into from

Conversation

hishamhm
Copy link
Member

@hishamhm hishamhm commented Jan 8, 2024

No description provided.

Copy link

github-actions bot commented Jan 8, 2024

Teal Playground URL: https://732--teal-playground-preview.netlify.app

@bjornbm
Copy link

bjornbm commented Jan 9, 2024

I'm excited for this new release, but struggle to grasp the interfaces and probably other changes. Basically I don't see much updates/explanation in tutorial.md, neither of interfaces not the move to nominal types (#711, #708).

@euclidianAce
Copy link
Member

From a quick glance I like the api changes and interfaces are a huge boon. Writing up some quick and dirty luv definitions (which is full of inheritance/interfaces) seems to be working well. I see interface where clauses are implemented as macros, which are also exposed via a new local macroexp foo(...) statement which after giving some thought is probably the best/lowest-amount-of-tying-users-of-teal-to-one-object-model way for a language like teal to add that sort of feature. Also nominal types are always a 👍 from me.

I do need to get back into the swing of working on teal related stuff, but I definitely fell into the got-a-real-job-and-now-have-less-time-to-work-on-hobby-projects trap that happens so often with open source.

All in all, looks great to me!

@catwell
Copy link
Contributor

catwell commented Jan 9, 2024

Same as @euclidianAce, real life (work + new kid) means I have little time for OSS but the changes I see in this branch are a lot of things I thought would be great for Teal.

Once it is a bit more stable I'll try it on my existing code bases in Teal.

@hishamhm
Copy link
Member Author

hishamhm commented Jan 9, 2024

@bjornbm tests and documentation are still pretty much missing, because I wanted to iterate as quickly as possible to experiment with the usability of these features... but once the dust settles we definitely need them!

@hishamhm
Copy link
Member Author

hishamhm commented Jan 9, 2024

@euclidianAce @catwell Thanks a lot for the feedback!! And, yeah, I totally get that sentiment — over the years I've accepted that my work on FOSS projects happens in bursts. When I find that I get a window of availability and motivation to work on this stuff, I try to get the most out of it. :)

For Teal, having a quiet time for the project since the last burst was a good thing as it allowed me to set priorities: seeing what are the gaps that people most often try to solve, etc. I think it's clear by now that the top two things missing in current Teal are interfaces and better nil handling. I don't think we'll get non-nilable types just yet, but it's the next thing on my mind. With --feat flags it should be easier to make gradual changes to the language in the future. This writeup has made the rounds recently and makes a good case for gradual language evolution via per-compilation-unit feature flags.

@hishamhm
Copy link
Member Author

hishamhm commented Jan 9, 2024

Also, speaking of writeups, it's funny that CI is failing because the tl.type_check function is exceeding the maximum number of upvalues per function in Lua 5.1. Looks like old Lua wasn't a fan of Carmack's long function style; I'll have to do some refactoring!

@hishamhm
Copy link
Member Author

hishamhm commented Jan 26, 2024

Update: it took me a big reorganization in d885f90 to get CI green. This is because the size of tl.tl started hitting size limits in both Lua 5.1 (number of upvalues) and Lua 5.4 (number of locals). The goal of the changes in this latest commit is to be able to finally break tl.tl into multiple files, but I wanted to do the reorg first to produce a sensible diff (which would let me more easily track the changes). The commit description includes more details on the internal changes.

@hishamhm
Copy link
Member Author

hishamhm commented Feb 2, 2024

Regarding "making the type system more nominal", here's one interesting example:

https://toot.kottman.xyz/@michal/111860362351389256

One thing I'm missing (or haven't yet found in docs) is "distinct type" (borrowing term from Nim) or integer based enum - e.g. local type LibraryErrorCode = distinct integer; function work():LibraryErrorCode

https://mastodon.social/@hisham_hm/111861339267098398

if you create a new nominal type for a base type like integer, it will be distinct across nominal types, but still be compatible with plain integer (so you can use the math. library etc)

This checks without errors in the master branch, but will check for Code against Age here in next:

local type Code = integer

local function get_code(): Code
end

local type Age = integer

local function get_age(): Age
end

local x: integer = get_code()
x = get_age()

local c: Code = get_code()
c = get_age()                         -- ERROR: in assignment: Age is not a Code

local a: Age = get_age()
a = get_code()                        -- ERROR: in assignment: Code is not a Age

@catwell
Copy link
Contributor

catwell commented Feb 11, 2024

I played a bit with the where clause on the current next branch, and I noticed that it doesn't work with generics. I mean that this works:

local type Success = record
    where self.error == false
    error: boolean
    value: integer
end

but not this:

local type Success = record<T>
    where self.error == false
    error: boolean
    value: T
end

It results in:

example.tl:2:11: missing type arguments in record<T>
example.tl:2:16: cannot index key 'error' in invalid 'self' of type self

Is that expected or do you intend to support it?

(Slightly related: can you release your FOSDEM slides? I know the video is probably broken, which is too bad, but the slides at least would be useful.)

@hishamhm
Copy link
Member Author

@catwell thanks for the test case! I haven't really worked on the relationship between generics and interfaces/where yet, so that's a good starting point.

Is that expected or do you intend to support it?

I intended where to work alongside is, as in record __ is __ where, but having where on its own might be workable for unions. As for the generic there, I intend to support this test case, but I expect I'll need to place some limitations in the interactions between is ___ subtyping and generics. I'll probably over-restrict to be on the safe side first, then see what can be relaxed.

@catwell
Copy link
Contributor

catwell commented Feb 20, 2024

(Slightly related: can you release your FOSDEM slides? I know the video is probably broken, which is too bad, but the slides at least would be useful.)

The video was not broken \o/

@uramer
Copy link

uramer commented Feb 27, 2024

How are where and __is intended to work for type declarations?

From: #692

> It took me a bit of digging the back history to try to remember why `.` and
> `:` have separate handlers. Of course, in Lua, `:` is just syntactic sugar. In
> Teal, however, we have in the language semantics separate concepts for
> functions and record-functions/methods, because the latter are statically
> bound to their records.
>
> For example, want to be able to detect that the programmer made a typo and a
> method name is invalid, and that means that we need, at one point of the code,
> to declare that the declarations of methods are done. So you can only do
> `function my_record:mymethod` in the same scope where you created your record,
> for instance.
>
> Internally, Teal does keep track if a function "is a method" (that is, if it
> was declared with `:` or `.`; in more recent versions, we even check if a
> function is method-like by having a first argument `self` with its own type).
> This is to keep the door open for future enhancements to the type system, such
> as interfaces (see this comment:
> #97 (comment)).
>
> So, it's an explicit decision to not make `:` just a syntactic sugar for `.`,
> like Lua.
Instead of treating nominal records nominally and all other nominal
types structurally, with this commit we treat all nominal types
nominally except for unions, which are treated structurally.

Give this branch a try in your codebase and let me know your impressions!
Now that unions may contain multiple table types, only infer
a table literal into the table type of a union if there's
a single table type in a union.
Accordingly, accept `is` checks on table types that declare `__is`.

We disallow unions mixing tables with and without `__is`. This is a limitation
because to lift it we would have to implement code that transforms this

```
local u = R1 | R2 | {number} -- R1 and R2 have __is, {number} doesn't

if u is {number} then
   -- ...
end
```

into (effectively)

```
local u = R1 | R2 | {number} -- R1 and R2 have __is, {number} doesn't

if not (u is R1 or u is R2) then
   -- ...
end
```

In other words, "is" testing for the one table/userdata item without __is
would have to be defined in terms of the negation of the disjunction of
all the other cases.
it is now handled by the parts that deal with module names:
`require` and the package loader.
I haven't these in ages, and in reality I just want to be able
to quickly Ctrl+F for "print" when I'm doing a quick debug. ;)
Several big changes, that were done in tandem, and which
would be too troublesome to break into separate commits.
The goal here is to ultimately be able to break tl.tl
into multiple files (because its size started hitting
limits in both Lua 5.1 (number of upvalues) and Lua 5.4
(number of locals). Here's a high-level summary of the
changes:

* new Errors record, encapsulating error-reporting concerns;

* all Type occurrences have unique objects reporting their
  locations (no more singletons for base types such as BOOLEAN
  and INVALID);

* some enums renamed for more consistency across Gen and Feat
  options;

* TypeCheckOptions and EnvOptions tables reorganized for
  easier forwarding of options across them;

* simplifications in the various function signatures
  of the public API;

* all Types and Nodes store filename, line and column
  location (`f`, `y`, `x`);

* Scope is now a record containing the variables map and
  unresolved items -- no more "@unresolved" pseudo-variable
  and `unresolved` pseudo-type for storing this data in
  the symbols table;

* `type_check` now uses a TypeChecker object for storing all state, instead of
  relying on closures and function nesting (that's a bit sad is it ended up
  spreading `self:` and extra function arguments everywhere, but I guess state
  management will be more explicit for others reading the code now...);

* all Fact objects have a Where location as well, and supressions of
  inference data in error messages for widened-back types is marked
  explicitly with `no_infer` instead of missing a `w` field;

* general simplification of the sourcing of error locations (though
  I would still like to improve that further);
The unwanted difference between the types for `f` and `g` in
the regression test from this commit was observed when fixing
the issue #736.
Do not over-constrain types with `unknown`, let `assert_is_a`
perform the check when t2 is `unresolved_emptytable_value`.
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.

None yet

6 participants