kcl-lang / kcl

KCL Programming Language (CNCF Sandbox Project). https://kcl-lang.io
https://kcl-lang.io
Apache License 2.0
1.67k stars 118 forks source link

[feature] Support for type arguments for convenient factory functions #1265

Closed dennybaa closed 6 months ago

dennybaa commented 6 months ago

Hello there! I've stumbled on a potentially useful scenario. It's actually already operational in KCL, but lacks syntax sugar and notion of that we are working with types. The bellow code implements a factory function:

schema Foo:
    foo: str = "foo"

schema Bar:
    bar: str = "bar"

factory = lambda $type: any -> Foo | Bar {
    func = $type
    print("typeof func: ", end='')
    print(func)
    print("---------------------")
    instance = func()
}
_foo = factory(Foo)
_bar = factory(Bar)
if typeof(_foo) == "Foo":
    foo = _foo as Foo

if typeof(_bar) == "Bar":
    bar = _bar as Foo

It works...) But not for everything, for example instances of types which have required attributes can not be created following the above approach.

Ideally to have a language feature to be able to do something like bellow:

factory = lambda $type: type -> Foo | Bar {
    $type { required = "foo" }
}

Along with this, it could make sense to have func type too...

What do you think of this @Peefy , could this be a good realistic idea? Thank you!

Peefy commented 6 months ago

I agree.

If we need to have factory for any schema and required attributes. We may have the following form

type {**required_attrs}

However, KCL currently check the schema type strictly. In the next version, I believe that you can impl the type factory and I will do some minor optimzed changes for KCL and show you the example later. 😃

Peefy commented 6 months ago

I've opened a PR to impl this: https://github.com/kcl-lang/kcl/pull/1269

But I have not added the type type for the arguments and used a runtime type type assert statement to verify the argument type at runtime.

schema Foo:
    foo: str

schema Bar:
    bar: str

factory = lambda type: any, attrs: {:} = {} -> Foo | Bar {
    assert typeof(type) == "type"
    func = $type
    instance = func() {**attrs}
}

_foo = factory(Foo, {foo = "foo"}) # Note we set attributes here.
_bar = factory(Bar, {bar = "bar"}) # Note we set attributes here.
if typeof(_foo) == "Foo":
    foo = _foo as Foo

if typeof(_bar) == "Bar":
    bar = _bar as Bar
dennybaa commented 6 months ago

Thanks a lot Peefy! Very solid :+1: