# ConstructorSpec

## Why

At the moment of writing, KotlinPoet doesn't have a ConstructorSpec. \
Because KotlinPoetDSL want's to allow building the code in an intuitive way, this means that the primary constructor should be able to define fields. \
Therefor, KotlinPoetDSL needs to have a ConstructorSpec

## Implementation

ConstructorSpec is a combination of a list of PropertySpecs, a FunctionSpec and a boolean indicates if it is a primary or a secondary constructor.\
Asking for the properties will either return its list with PropertySpecs or an empty list, based on if it's a primary or secondary constructor.

{% hint style="info" %}
the val/var - keywords will be hidden (e.g. the properties will be hidden) if the&#x20;
{% endhint %}

## Construction

You can build the constructor in a view ways:

* implicit from the clazz-call
* using buildConstructor
* for interoperability, using a funSpec.

### Implicit from the clazz-call

When creating a class, you can create a primary constructor implicitly from the clazz-function:

```kotlin
file("", "Hello"){
    //--------------------- doesn't create a primary construcor
    clazz("First") // class First
    
    
    //-------------------- interoperability
    val param = ParameterSpec.builder("par", String::class).build()
    clazz("Second", param)// class Second(par: String)
    
    val immutable = PropertySpec.builder("immutable", String::class).build()
    clazz("Third", immutable) //class Third(val prop:  String)

    val mutableProp = PropertySpec.varBuilder("mutable", String::class).build()
    clazz("Fourth", mutableProp) //class Fourth(var prop:  String)
    
    
    //------------------- KotlinPoetDSLs way
    clazz("Fifth", "prop" of String::class) // Fifth(prop : String)
    clazz("Sixth", "prop" varOf String::class) // Sixth(var prop : String)
    clazz("Sixth", "prop" valOf String::class) // Sixth(val prop : String)
}
```

### Stand-alone using buildConstructor

You can create a standalone ConstructorSpec using `createConstructor`.\
Inside the function, you can use the real DSL to create a constructor.\
Inside the lambda, you need to return a ConstructorSpec, so the curly brackets.\
Technically it's not needed, but overhere I wanted to be strict.

```kotlin
fun main(args: Array<String>) {
    val constr1 = createConstructor {
        private.constructor("prop" valOf String::class) {}
    }
    constr1 // private constructor(prop : String)
    constr1.toPrimary() // private constructor(val prop : String)

    val constr2 = createConstructor {
        internal.primary.constructor("prop" varOf String::class)
    }
    constr2 // internal primary constructor(var prop : String)

    val constr3 = createConstructor {
        constructor("prop" of String::class){}
    }
    constr3 //constructor(prop : String)
    constr3.toPrimary() //primary constructor(prop : String)
    
    createConstructor {
        constructor("prop" of String::class).thiz("prop"){}
    } //constructor(prop: kotlin.String) : this(prop)

    createConstructor {
        constructor("prop" of String::class).zuper("prop"){}
    } //constructor(prop: kotlin.String) : super(prop)
}
```

{% hint style="danger" %}
before V0.2, the toPrimary() is not checked for thizz and zuper, meaning it will fail, once it is added to the class.
{% endhint %}

### Adding Stand-alone constructors to the class

you can add those to the class on the following way:

```kotlin
val constr1 = buildConstructor {
        primary.constructor()
    }
    file("", "HelloWorld") {
        clazz("One") {
            // will always pass the constructor like it is created
            // this means private is ignored
            private.accept(constr1) 
        }
        
        
        clazz("Two") {
            // will be dropped in V0.2, due to "strange" working
            public.constructor(constr1) // will merge modifiers
        }
        
        clazz("Three"){
            accept(constr1.buildUpon { 
                addModifier(KModifier.PUBLIC)
            })
        }
    }
```

in V0.2, the code of public constructor will be replaced with:

```kotlin
constr1.attach{ 
    addModifiers(KModifier.PUBLIC)
}
```

Then you can create the function constructor yourself, or give it a different implementation that makes sense to you.

## Interoperability

ConstructorSpec is interoperable with KotlinPoet

### Creating ConstructorSpec

allowed at the moment

```kotlin
val func = FunSpec.constructorBuilder().addParameter(
    ParameterSpec.builder("hi", String::class).build()
).build()

val secondaryConstructor = func.toConstructor()
val primaryConstructor = func.toPrimaryConstructor(
    ("hi" valOf String::class).toPropertySpec()
)
```

allowed in V0.2

```kotlin
val option1 = func.toPrimaryConstructor(
    "one" of String::class, "two" valOf String::class
)

val option2 = func.toPrimaryConstructor(
    "hi" to Variable.Mutability.MUTABLE, //where you import MUTABLE, of course ;-)
    "two" to  Mutability.NONE
)
```

### Using ConstructorSpec

```kotlin
val const = buildConstructor { 
    private.primary.constructor(
        "arg1" valOf String::class,
        "arg2" varOf Int::class
    )
}

TypeSpec.classBuilder("Clazz")
    .addConstructor(const)
    .build()
//class Clazz(val arg1: String, var arg2 : Int)
```

### Getting KotlinPoetTypes

As defined in the intro, the types are already from KotlinPoet:

```kotlin
val const = buildConstructor {
    private.constructor(
        "arg1" valOf String::class,
        "arg2" varOf Int::class
    ){}
}

const.funSpec // FunSpec: private constructor(arg1: kotlin.String, arg2: kotlin.Int)

const.toPrimary().properties 
// Properties:  [val arg1: kotlin.String = arg1\n, var arg2: kotlin.Int = arg2\n]
```

In 0.2, `toPrimary` is no longer needed: a field allProperties is added, where all the properties are visible.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kotlinpoetdsl.devhaan.nl/differences-to-kotlinpoet/constructorspec.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
