kcl icon indicating copy to clipboard operation
kcl copied to clipboard

[Enhancement] KCL user interface simplification and consistency including grammar and sematic

Open Peefy opened this issue 3 years ago • 2 comments

Background

The current KCL syntax and semantics are complex. In order to further improve the usability of KCL, ensure logical consistency, and reduce the difficulty of getting started, it is necessary to simplify the functions that are not commonly used in KCL according to the scenarios, and support more use scenarios with the least language features.

Overview

The simplification of KCL can be mainly divided into three aspects:

Consistency improvement

  • Be consistent with certain expression syntax styles
  • Keep certain semantic styles consistent, such as the use of operators. Try to ensure that one operator has only one semantic

Grammar simplification

  • Delete infrequently used functions
  • Enhance common functions with grammatical sugar

Semantic simplification

  • Remove some uncommon semantics and corresponding checking programs, so that the internal programs of KCLVM are more lightweight and the program operation efficiency is improved

Goals

  • No obvious ambiguity in grammar and semantics.
  • Reduce the number of syntax nodes by 3 without reducing the original language capability.

Simplification List

  • [x] Unified content and style of KCL error messages. https://github.com/KusionStack/KCLVM/issues/527
  • KCL has too many keywords (e.g., schema, mixin, protocol, rule), and the concept is complex and needs to be simplified. There is a threshold for using the mixin keyword.
  • Unification Enhancement between configurations in different schema and mixins.
  • The style of lambda/quant expressions is inconsistent with that of the schema. Lambda/quant expressions are curly brackets and schema is indented
  • The syntax of lambda parameters and schema is inconsistent (lambda has no square brackets, the schema has square brackets), lambda x: int, y: int -> int=>lambda [x: int, y: int] -> int {...}
  • The built-in system library needs to be further unified and enhanced, and common function support should be added to solve user pain points
  • The initial value of a single string literal is simplified name: "Alice"="Alice", which is easy to cause confusion
  • [x] Semantic simplification of operators (Python tricks) #1124
    • Disable the use and operation of bool variables 1+True
    • Prohibit comparison between list variables [0]<[1]
  • any type and any keywords have the same name, which is easy to be confused.
  • KCL currently allows both tabs and spaces, which is consistent with Python. As a DSL, it should strive to unify the style and only allow spaces.
  • _x represents hidden (will not output to YAML/JSON) and mutable, perhaps there is a better distinction between these two points in terms of language, French, and semantics
  • The verification method for top-level attributes and schema is inconsistent: the grading attributes, function parameters, and schema fields are unified
  • How to re-export the attributes of the imported package and whether to also provide import/export capabilities
  • [x] Plan empty list. #511
  • [x] Top-level schema value plan. #545
schema Pod:
     apiVersion = "v1"
     metadata: {str:}

Pod {
    metadata.name = "name"
}     
apiVersion: v1
metadata:
  name: name
  • KCL metadata.name = "123" v.s. metadata: name: "123".
  • Inconsistent visibility behavior between modules.
- pkg
    - file1.k
    - file2.k
- file3.k

In pkg, file1 and file2 are not visible to each other. In other words, when compiling file2, the definition in file1 cannot be used directly. But if import pkg in file3, file2 and file1 are visible to each other

  • The semantics of the as keyword need further clarification and clarification. The as keyword should consider both type guarding and runtime type conversion assertions
  • The semantic fusion of dict, record, and schema is not clear, and the implementation is relatively complex, more consideration of the record type of Typescript.
  • Optional attributes of schema? Should be part of the type system, rather than runtime type checking, to help users write better code.
  • The schema is bound to both type definitions and runtime constraints, which can be designed separately and combined to achieve lazy validation.

Principles for Redesign

  • Simple and closer to json-like and ts-like rather than having more Python trips such as indentation and inverted comprehension.
  • The core elements of the redesigned KCL are still Schema, Config, Lambda, and Rule, which are determined by the KCL's scene and positioning.

A Possible Redesign

Grammar

  • Schema (Including Objects and Records)
type ContainerMap = {
    [str]: Container
}

type WebService {
      name: str
      containers: ContainerMap # Or using `{[str]: Container}` directly
}
  • Config
metadata = {
     name = "service"
     labels.key = "value"
}
service: WebService = {
     name = "Alice"
}
  • Lambda
render_web_service = lambda (s: WebService) -> Deployment {}
  • Rule
schema Request {
      path: str
      method: str
}

rule Allow for Request  {
        path in ["users"]
        method == "POST"
}

Peefy avatar Dec 15 '22 05:12 Peefy

I just wanted to mention an issue I'm having - not sure how to fix it and I thought someone here might be able to put out a quick fix.

A feature was recently added: https://github.com/kcl-lang/kcl/issues/545

It works very well except when I try to import a file into another file. I can't use any of the values as root-level variables from the file like I can with other files that do not use types. I have to first assign the output to a root-level variable and use that. I would like to just be able to import a typed config and use its values as root-level variables.

karlhepler avatar May 21 '24 13:05 karlhepler

Hello, @karlhepler

Generally, we use root-level variables in the entry files such as main.k and we use the import statement in the main.k and import another file such as pkg.k

  • main.k
import .pkg
import manifests

pkg.pod # or using the function manifests.yaml_stream([pkg.pod]): https://www.kcl-lang.io/docs/reference/model/manifests#yaml_stream
  • pkg.k
pod = Pod {} # instead of `Pod {}` without `pod =`

If you want to use main.k as an entry point and pkg.k as an entry point, my suggestion is to maintain a common module so that both main.k and pkg.k can directly import it instead of main.k importing pkg.k

  • common
pod = Pod {}
  • pkg.k
import common

common.pod
  • main.k
import common

common.pod

Peefy avatar May 21 '24 14:05 Peefy