# Traits
#trait #traits #edn #shards
*tl;dr*
Traits are the foundation for general and generic interoperability, as well as forward compatible code evolution.
## Trait Declaration
```clojure
(trait example
:shards1
{:Type Type.Shards
:Requires ["variable1" Type.Int]
:Inputs [Type.Int]
:Output Type.Int}
:int1 [Type.None Type.Int]
:float1 Type.Float)
```
### Things to notice
Instead of `[Type.None]` a single type can be defined in a simplified way without the vector, like `Type.None`.
#### *shards1*
This is an example of how we define more complex entries.
Instead of a simple `Type.` definition we use a map `{}` to define the complex characteristics of the shards flow.
Notice that a wire can have different types of `Inputs` but a single type of `Output`.
## Trait Definition
```clojure
(deftrait example
:shards1 (-> (Math.Add .variable1))
:int1 10
:float1 22.2)
```
What `deftrait` does internally is:
* In the current scripting (mal) `environment` it will insert `example` as a map containing those keywords (`:shards1`, etc.).
Basically other code running after will find the trait `example` as a map and can access the contract items.
E.g.
```clojure
(defwire compute
11 = .variable1
10
(get example :shards1)
(Assert.Is 21)
(Math.Add (get example :int1))
(Assert.Is 31))
```
**TODO**
We need to validate that `deftrait` and the defined items actually follow 1:1 the `trait` specification.
#### Remarks
If a trait definition is contained in a pure **Shards** `Table` it could be implemented in any supported language other than Shards Script such as C or Rust. **This is not the case for now, we will see if it should be. For now the definition is in Shards Script EDN, this has greater flexibility.**
## More concrete examples
### A weapon
#### Damaging trait
```clojure
(trait Damaging
; a pure value would be hard to express in a interoperable way
:damage-multiplier {:Type Type.Float :Min 0.0 :Max 1.0})
```
#### Weapon script definition
```clojure
(deftrait Damaging
:damage-multiplier 0.1)
...
```
#### A game able to load `Damaging` trait weapons
```clojure
...
(defwire logic
...
max-damage (Math.Multiply (get Damaging :damage-multiplier))
...)
...
```
### Discord Bot
#### Trait for a custom bot behavior
```clojure
(trait Discord-Bot
:token Type.String
:on-message-create [Type.None {:Type Type.Shards :Inputs Type.Table}])
```
#### Actual code
```clojure
(def bot-token (get Discord-Bot :token))
(def discord-dispatch
(->
(Take "t") (ExpectString)
(Match ["MESSAGE_CREATE" (get Discord-Bot :on-message-create)
nil nil])))
(def discord-gateway "gateway.discord.gg")
(def discord-gateway-target "/?v=6&encoding=json")
; gateway opcodes
(def op-identify 2)
(def op-heartbeat 1)
(def op-hello 10)
(def op-heartbeat-ack 11)
(def op-dispatch 0)
(defloop discord-bot-reader
(WebSocket.ReadString .ws-discord-bot) (FromJson) (ExpectTable) = .payload
(Take "op") (ExpectInt)
(Match [op-heartbeat-ack nil
op-dispatch (-> .payload discord-dispatch)
nil (-> .payload (Log "unknown op"))]))
(defloop heartbeat
{"op" op-heartbeat "d" .discord-session} (ToJson)
(WebSocket.WriteString .ws-discord-bot)
(Pause 4.0))
(defloop discord-bot-loop
(Setup
(WebSocket.Client "ws-discord-bot" discord-gateway
:Target discord-gateway-target :Secure true :Port 443)
; receive and handle hello
(WebSocket.ReadString .ws-discord-bot) (FromJson) (ExpectTable)
(Log "Hello payload")
(Take "op") (Assert.Is op-hello) ; ensure it's a hello
; craft our hello
{"op" op-identify
"d" {"token" bot-token
"properties" {"$os" "any"
"$browser" "shards"
"$device" "unknown"}
"compress" false}}
(ToJson) (Log "Sending log-in") (WebSocket.WriteString .ws-discord-bot)
(WebSocket.ReadString .ws-discord-bot) (Log "Login response")
(FromJson) (ExpectTable)
(Branch [heartbeat discord-bot-reader]))
(defmesh root)
(schedule root discord-bot-loop)
(run root 0.1)
```