From c3366590ade2b21ca1266ec8602475335e30c687 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 19:00:49 +0200 Subject: [PATCH 01/11] Create udtf-classname.md --- docs/udtf-classname.md | 124 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 docs/udtf-classname.md diff --git a/docs/udtf-classname.md b/docs/udtf-classname.md new file mode 100644 index 000000000..445d9148d --- /dev/null +++ b/docs/udtf-classname.md @@ -0,0 +1,124 @@ +# type classname method utility + +## Summary + +Add a new method to ``type`` for User Defined Type Functions, ``type.classname``. Which will retrieve a ``ExternType``'s name. + +Or any other way to get the classname. + +## Motivation + +Why are we doing this? What use cases does it support? What is the expected outcome? + +**Use cases:** +- A lazy (but therefore also quick way?) to filter out class based types (e.g. from ``declare class``) + - e.g. class based types that are not accessible through ``types.`` such as ``vector`` for instance + - embedders such as Roblox, may also have class based types that can't be filtered without passing a type into the function. +- Useful for debug purposes when using ``print`` within a type function. + + +Currently, you can only do this, or other tricks: + +```lua +--!strict +type function isClass(input, whatToCheck) + return (input == whatToCheck) +end + +type function vectorOnly(input, whatToCheck) + local matches = isClass(input, whatToCheck) + if (matches) then + print(matches, "It is a vector type") + return input + end + + return types.unknown +end + +type a = vectorOnly +``` + + +**What it would solve:** +- You don't have to pass in a sample of a type that you want to check, if it is a class +- Drawback: If two classes are ever named the same, it would be an inaccurate check, hence why above it mentions _"lazy"_ + + +## Design + +This is the bulk of the proposal. Explain the design in enough detail for somebody familiar with the language to understand, and include examples of how the feature is used. + +I tried an implementation: +- https://github.com/karl-police/luau/commit/26b66c79d4d68e5f18601f619082b4d9b62473aa +- https://github.com/karl-police/luau/commit/03bef7130a9cdbf550b6e0bbcdaf5c9a562ef427 + +This is its **Unit Test**. + +```lua +declare class CustomClass + function testFunc(self): number +end + +type function pass(arg, compare) + if (arg:is("class")) then + assert(arg:classname() == compare:value()) + end + + return types.unknown +end + +type a = pass +type b = pass +``` + + +### ``type`` changes + +| New/Update | Instance Methods | Type | Description | +| ------------- | ------------- | ------------- | ------------- | +| New | `classname()` | `string?` | Returns the name of a class or 'nil' if there's no name. | + +**OR** + +| New/Update | Instance Methods | Type | Description | +| ------------- | ------------- | ------------- | ------------- | +| Update | `name()` | `string?` | Returns the name of a generic or class, or 'nil' if there's no name. | + + + +### Example + +```lua +declare class CustomClass + function testFunc(self): number +end + +type function onlyClassName(input) + assert(input:is("class")) + + if (input:classname() == "CustomClass") then + -- ... + return input + else + error("class is not named CustomClass") + end +end + +type a = onlyClassName +``` + + +## Drawbacks + +The implementation for ``type:name()`` seems to copy the Generic Name. + +If ``type:classname()`` would do this as well, maybe it would be catastrophic to memory. +In my first implementation, it doesn't do that though within the "serialize" process, instead it's just "read on request", but without caching. + +It is currently confusing that there's ``:value()`` but the function name itself, doesn't speak out _"Hey, I am only for singletons"_ or similar. +Hence why I am wondering whether if something like this should exist, whether it should be ``:classname()`` or ``:name()`` + + +## Alternatives + +An alternative would be to have the ability to require "upvalue" or external types into the type function. From 82541c55dddfeeed568f6fc3ed3fa79ca2d38259 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 19:45:08 +0200 Subject: [PATCH 02/11] Update udtf-classname.md --- docs/udtf-classname.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/udtf-classname.md b/docs/udtf-classname.md index 445d9148d..3f35a039e 100644 --- a/docs/udtf-classname.md +++ b/docs/udtf-classname.md @@ -110,9 +110,10 @@ type a = onlyClassName ## Drawbacks -The implementation for ``type:name()`` seems to copy the Generic Name. +I don't know if a generic can be directly passed into a type function and then use ``type:name()``. +But Generic Names are being collected. -If ``type:classname()`` would do this as well, maybe it would be catastrophic to memory. +If ``type:classname()`` would do this as well, maybe it would be inefficient for memory, because the name already exists. In my first implementation, it doesn't do that though within the "serialize" process, instead it's just "read on request", but without caching. It is currently confusing that there's ``:value()`` but the function name itself, doesn't speak out _"Hey, I am only for singletons"_ or similar. From 2d3fcb621a96339418586a90dcd1c8c1ecb8d611 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 20:23:13 +0200 Subject: [PATCH 03/11] Update and rename udtf-classname.md to udtf-type-external-name.md --- ...lassname.md => udtf-type-external-name.md} | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) rename docs/{udtf-classname.md => udtf-type-external-name.md} (64%) diff --git a/docs/udtf-classname.md b/docs/udtf-type-external-name.md similarity index 64% rename from docs/udtf-classname.md rename to docs/udtf-type-external-name.md index 3f35a039e..764a7d19c 100644 --- a/docs/udtf-classname.md +++ b/docs/udtf-type-external-name.md @@ -1,19 +1,17 @@ -# type classname method utility +# type externname method utility ## Summary -Add a new method to ``type`` for User Defined Type Functions, ``type.classname``. Which will retrieve a ``ExternType``'s name. +Add a new method to ``type`` for User Defined Type Functions, ``type.externname``. Which will retrieve a ``ExternType``'s name. -Or any other way to get the classname. +Or any other way to get the name of an external type. ## Motivation -Why are we doing this? What use cases does it support? What is the expected outcome? - **Use cases:** -- A lazy (but therefore also quick way?) to filter out class based types (e.g. from ``declare class``) - - e.g. class based types that are not accessible through ``types.`` such as ``vector`` for instance - - embedders such as Roblox, may also have class based types that can't be filtered without passing a type into the function. +- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``) + - e.g. external based types that are not accessible through ``types.`` such as ``vector`` for instance + - embedders such as Roblox, may also have external based types that can't be filtered without passing a type into the function. - Useful for debug purposes when using ``print`` within a type function. @@ -21,12 +19,12 @@ Currently, you can only do this, or other tricks: ```lua --!strict -type function isClass(input, whatToCheck) +type function isType(input, whatToCheck) return (input == whatToCheck) end type function vectorOnly(input, whatToCheck) - local matches = isClass(input, whatToCheck) + local matches = isType(input, whatToCheck) if (matches) then print(matches, "It is a vector type") return input @@ -40,8 +38,8 @@ type a = vectorOnly **What it would solve:** -- You don't have to pass in a sample of a type that you want to check, if it is a class -- Drawback: If two classes are ever named the same, it would be an inaccurate check, hence why above it mentions _"lazy"_ +- You don't have to pass in a sample of a type that you want to check +- Drawback: If two ExternTypes are ever named the same, it would be an inaccurate check, hence why above it mentions _"lazy"_ ## Design @@ -61,7 +59,7 @@ end type function pass(arg, compare) if (arg:is("class")) then - assert(arg:classname() == compare:value()) + assert(arg:externname() == compare:value()) end return types.unknown @@ -76,13 +74,13 @@ type b = pass | New/Update | Instance Methods | Type | Description | | ------------- | ------------- | ------------- | ------------- | -| New | `classname()` | `string?` | Returns the name of a class or 'nil' if there's no name. | +| New | `externname()` | `string?` | Returns the name of an ExternType or 'nil' if there's no name. | **OR** | New/Update | Instance Methods | Type | Description | | ------------- | ------------- | ------------- | ------------- | -| Update | `name()` | `string?` | Returns the name of a generic or class, or 'nil' if there's no name. | +| Update | `name()` | `string?` | Returns the name of a generic or ExternType, or 'nil' if there's no name. | @@ -93,18 +91,18 @@ declare class CustomClass function testFunc(self): number end -type function onlyClassName(input) +type function onlyCustomClass(input) assert(input:is("class")) - if (input:classname() == "CustomClass") then + if (input:externname() == "CustomClass") then -- ... return input else - error("class is not named CustomClass") + error("type is not named CustomClass") end end -type a = onlyClassName +type a = onlyCustomClass ``` @@ -113,11 +111,11 @@ type a = onlyClassName I don't know if a generic can be directly passed into a type function and then use ``type:name()``. But Generic Names are being collected. -If ``type:classname()`` would do this as well, maybe it would be inefficient for memory, because the name already exists. +If ``type:externname()`` would do this as well, maybe it would be inefficient for memory, because the name already exists. In my first implementation, it doesn't do that though within the "serialize" process, instead it's just "read on request", but without caching. It is currently confusing that there's ``:value()`` but the function name itself, doesn't speak out _"Hey, I am only for singletons"_ or similar. -Hence why I am wondering whether if something like this should exist, whether it should be ``:classname()`` or ``:name()`` +Hence why I am wondering whether if something like this should exist, whether it should be ``:externname()`` or ``:name()`` ## Alternatives From 8d151b95526c77c2c2a1080fc18ae46cce45e681 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 20:30:56 +0200 Subject: [PATCH 04/11] Update and rename udtf-type-external-name.md to udtf-type-extern-name.md --- docs/{udtf-type-external-name.md => udtf-type-extern-name.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename docs/{udtf-type-external-name.md => udtf-type-extern-name.md} (93%) diff --git a/docs/udtf-type-external-name.md b/docs/udtf-type-extern-name.md similarity index 93% rename from docs/udtf-type-external-name.md rename to docs/udtf-type-extern-name.md index 764a7d19c..1db8e7ef3 100644 --- a/docs/udtf-type-external-name.md +++ b/docs/udtf-type-extern-name.md @@ -9,7 +9,7 @@ Or any other way to get the name of an external type. ## Motivation **Use cases:** -- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``) +- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``, or ``type a`` passed into a function) - e.g. external based types that are not accessible through ``types.`` such as ``vector`` for instance - embedders such as Roblox, may also have external based types that can't be filtered without passing a type into the function. - Useful for debug purposes when using ``print`` within a type function. @@ -111,7 +111,7 @@ type a = onlyCustomClass I don't know if a generic can be directly passed into a type function and then use ``type:name()``. But Generic Names are being collected. -If ``type:externname()`` would do this as well, maybe it would be inefficient for memory, because the name already exists. +If ``type:externname()`` would copy the ``externType->name`` into the TypeFunction's ExternType, maybe it would be inefficient for memory, because the name already exists. In my first implementation, it doesn't do that though within the "serialize" process, instead it's just "read on request", but without caching. It is currently confusing that there's ``:value()`` but the function name itself, doesn't speak out _"Hey, I am only for singletons"_ or similar. From 0e29ea0861352a5923fc28b446d85d063773fcf7 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 20:48:48 +0200 Subject: [PATCH 05/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index 1db8e7ef3..47ec5c505 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -9,7 +9,7 @@ Or any other way to get the name of an external type. ## Motivation **Use cases:** -- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``, or ``type a`` passed into a function) +- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``) - e.g. external based types that are not accessible through ``types.`` such as ``vector`` for instance - embedders such as Roblox, may also have external based types that can't be filtered without passing a type into the function. - Useful for debug purposes when using ``print`` within a type function. From af4edc130c81b718963d292a56df7bb9dac4ceed Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 21:30:04 +0200 Subject: [PATCH 06/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index 47ec5c505..e5ca33eae 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -9,7 +9,7 @@ Or any other way to get the name of an external type. ## Motivation **Use cases:** -- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``) +- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``/``declare extern type``) - e.g. external based types that are not accessible through ``types.`` such as ``vector`` for instance - embedders such as Roblox, may also have external based types that can't be filtered without passing a type into the function. - Useful for debug purposes when using ``print`` within a type function. @@ -53,7 +53,7 @@ I tried an implementation: This is its **Unit Test**. ```lua -declare class CustomClass +declare class CustomExternType function testFunc(self): number end @@ -65,7 +65,7 @@ type function pass(arg, compare) return types.unknown end -type a = pass +type a = pass type b = pass ``` @@ -87,22 +87,22 @@ type b = pass ### Example ```lua -declare class CustomClass +declare class CustomExternType function testFunc(self): number end -type function onlyCustomClass(input) +type function onlyCustomExternType(input) assert(input:is("class")) - if (input:externname() == "CustomClass") then + if (input:externname() == "CustomExternType") then -- ... return input else - error("type is not named CustomClass") + error("type is not named CustomExternType") end end -type a = onlyCustomClass +type a = onlyCustomExternType ``` From 48e507b918ba61440398286093b46648e73ba80c Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 21:59:10 +0200 Subject: [PATCH 07/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index e5ca33eae..501679714 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -9,7 +9,7 @@ Or any other way to get the name of an external type. ## Motivation **Use cases:** -- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare class``/``declare extern type``) +- A lazy _(but therefore also quick way?)_ to filter out extern types (e.g. from ``declare extern type``) - e.g. external based types that are not accessible through ``types.`` such as ``vector`` for instance - embedders such as Roblox, may also have external based types that can't be filtered without passing a type into the function. - Useful for debug purposes when using ``print`` within a type function. @@ -87,7 +87,7 @@ type b = pass ### Example ```lua -declare class CustomExternType +declare extern type CustomExternType function testFunc(self): number end From a191c6b463a9d3a32e450f8eca7795ae512a0e6b Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 22:04:48 +0200 Subject: [PATCH 08/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index 501679714..cbb9eed8a 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -53,7 +53,7 @@ I tried an implementation: This is its **Unit Test**. ```lua -declare class CustomExternType +declare extern type CustomExternType with function testFunc(self): number end @@ -87,7 +87,7 @@ type b = pass ### Example ```lua -declare extern type CustomExternType +declare extern type CustomExternType with function testFunc(self): number end From 07705a693ecb6fd28e679bb4c6358e3f336b08d2 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 22:05:45 +0200 Subject: [PATCH 09/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index cbb9eed8a..f60cb917d 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -4,8 +4,6 @@ Add a new method to ``type`` for User Defined Type Functions, ``type.externname``. Which will retrieve a ``ExternType``'s name. -Or any other way to get the name of an external type. - ## Motivation **Use cases:** From b46361fec514f96488b1c799bf18baada5b3e298 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 14 Jul 2025 22:06:09 +0200 Subject: [PATCH 10/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index f60cb917d..85f98416d 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -1,4 +1,4 @@ -# type externname method utility +# type ``externname`` method ## Summary From 86a14723ab10d581ce55d9a4b539200269421027 Mon Sep 17 00:00:00 2001 From: karl-police Date: Sun, 24 Aug 2025 21:15:51 +0200 Subject: [PATCH 11/11] Update udtf-type-extern-name.md --- docs/udtf-type-extern-name.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/udtf-type-extern-name.md b/docs/udtf-type-extern-name.md index 85f98416d..f6fa65b46 100644 --- a/docs/udtf-type-extern-name.md +++ b/docs/udtf-type-extern-name.md @@ -56,7 +56,7 @@ declare extern type CustomExternType with end type function pass(arg, compare) - if (arg:is("class")) then + if (arg:is("extern")) then assert(arg:externname() == compare:value()) end @@ -90,7 +90,7 @@ declare extern type CustomExternType with end type function onlyCustomExternType(input) - assert(input:is("class")) + assert(input:is("extern")) if (input:externname() == "CustomExternType") then -- ...