# How to avoid flattening of fields in Record?

**URL:** <https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79>\
**Category:** Clash Help\
**Created:** [May 14, 2025, 3:35pm UTC](https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79 "2025-05-14T15:35:58Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bipinoli](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/bipinoli/32/25_2.png) [@Bipinoli](https://clash-lang.discourse.group/u/Bipinoli)\
**Post date:** [May 14, 2025, 3:35pm UTC](https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79/1 "2025-05-14T15:35:58Z")

</div>

Hi, for the code below:

```auto
module Spec where

import Clash.Prelude
import Clash.Annotations.TopEntity

data ValidInt = ValidInt {
    value :: Int, 
    valid :: Bool
} deriving (Generic, NFDataX)

data Inputs = Inputs {
    input0 :: ValidInt
} deriving (Generic, NFDataX)

machine :: HiddenClockResetEnable dom => Signal dom Inputs -> Signal dom Int
machine inputs = pure 42

topEntity :: Clock System -> Reset System -> Enable System -> 
    Signal System Inputs -> Signal System Int
topEntity clk rst en inputs = exposeClockResetEnable (machine inputs) clk rst en

```

Clash flattens the inputs in the generated verilog like this:

```auto
/* AUTOMATICALLY GENERATED VERILOG-2001 SOURCE CODE.
** GENERATED BY CLASH 1.8.2. DO NOT MODIFY.
*/
`default_nettype none
`timescale 100fs/100fs
module topEntity
    ( // Inputs
      input wire clk // clock
    , input wire rst // reset
    , input wire en // enable
    , input wire [64:0] inputs

      // Outputs
    , output wire signed [63:0] result
    );

  assign result = 64'sd42;
endmodule

```

I want two different wires instead. Something like:

```auto
input wire [63:0] input0_0; -- value
input wire input0_1; -- valid

```

Is there a way to do this?

As a potential solution, I tried annotating TopEntity like:

```auto
{-# ANN topEntity
  (Synthesize
    { 
        t_name = "myModule",
        t_inputs = [ 
            PortName "clk",
            PortName "rst",
            PortName "en",
            PortProduct "inputs" [
                PortProduct "input0" [
                    PortName "value",
                    PortName "valid"
                ]
            ]
        ],
        ...
    }) #-}

```

However, it gives me the error:

```auto
*** Exception: Saw a PortProduct in a Synthesize annotation:

  PortProduct "inputs" [PortProduct "input0" [PortName "value",PortName "valid"]]

but the port type:

  Product "Spec.ValidInt" (Just ["value","valid"]) [Signed 64,Bool]

is not a product!
CallStack (from HasCallStack):
  error, called at src/Clash/Netlist/Util.hs:1946:8 in clash-lib-1.8.2-8ZihzcIDdiCEsBBuhDMByd:Clash.Netlist.Util
  expandTopEntityOrErrM, called at src/Clash/Netlist/Util.hs:790:8 in clash-lib-1.8.2-8ZihzcIDdiCEsBBuhDMByd:Clash.Netlist.Util
  mkUniqueNormalized, called at src/Clash/Netlist.hs:267:9 in clash-lib-1.8.2-8ZihzcIDdiCEsBBuhDMByd:Clash.Netlist
  genComponentT, called at src/Clash/Netlist.hs:241:41 in clash-lib-1.8.2-8ZihzcIDdiCEsBBuhDMByd:Clash.Netlist
  genComponent, called at src/Clash/Netlist.hs:119:9 in clash-lib-1.8.2-8ZihzcIDdiCEsBBuhDMByd:Clash.Netlist

```

I also tried annotating the `ValidInt` with `InlinePrimitive` but I couldn’t make that work and it felt a bit clunky.

I know if I change `Inputs` into a tuple, Clash doesn’t flatten like this, but I prefer using Record due to the 12-item limit of tuple size in Clash. Also, when I have multiple input fields in `Inputs` Clash doesn’t flatten like this.

Is there a clean way to deal with this?

---

<div class="post-metadata">

**Author:** ![DigitalBrains](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/digitalbrains/32/28_2.png) [@DigitalBrains](https://clash-lang.discourse.group/u/DigitalBrains)\
**Post date:** [May 14, 2025, 3:54pm UTC](https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79/2 "2025-05-14T15:54:37Z")

</div>

I’d suggest just making your top entity map between your Clash data types and the way you want them presented on the ports of the logical entity. So just something like:

```haskell
topEntity ::
  Clock System ->
  Reset System ->
  Enable System ->
  Signal System Int ->
  Signal System Bool ->
  Signal System Int
topEntity clk rst en value0 valid0 =
  exposeClockResetEnable (machine inputs) clk rst en
 where
  inputs = Inputs <$> (ValidInt <$> value0 <*> valid0)
{-# OPAQUE topEntity #-}

```

or in a more record-y style:

```haskell
topEntity clk rst en value0 valid0 =
  exposeClockResetEnable (machine inputs) clk rst en
 where
  inputs = construct <$> value0 <*> valid0
  construct value1 valid1 =
    Inputs
      { input0 =
          ValidInt
            { value = value1
            , valid = valid1
            }
      }

```

You can also use lenses or barbies to make it prettier.

You _can_ use `PortProduct` to deconstruct types which have only one field; this is mostly intended for deconstructing `Maybe` into a `valid` flag and a data value, but you can do it for any sum-of-products type with just one field in total, splitting it into constructor bits and field bits:

```haskell
module PortProduct where

import Clash.Prelude

data T a = A | B a | C

sop ::
  BitVector 2 ->
  Unsigned 4 ->
  T (Unsigned 4)
sop 0 _ = A
sop 1 x = B x
sop _ _ = C
{-# ANN sop (
  Synthesize
    { t_name = "sop"
    , t_inputs = [PortName "si", PortName "di"]
    , t_output = PortProduct "o" [PortName "s", PortName "d"]
    }) #-}

```

This has the same shape for inputs and output even though the output is a custom data type.

---

<div class="post-metadata">

**Author:** ![DigitalBrains](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/digitalbrains/32/28_2.png) [@DigitalBrains](https://clash-lang.discourse.group/u/DigitalBrains)\
**Post date:** [May 14, 2025, 4:03pm UTC](https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79/3 "2025-05-14T16:03:02Z")

</div>

> [@Bipinoli](#):
>
> I also tried annotating the `ValidInt` with `InlinePrimitive`

A primitive is a function, and of course, a data constructor is a function, but I’ve never seen anyone make a data constructor a black box… also, I’m fairly sure a black box has no influence on the ports of a logical entity, even if you create a black box for the data constructor, the ports would still look the same.

> [@Bipinoli](#):
>
> However, it gives me the error:
> 
> ```auto
> *** Exception: Saw a PortProduct in a Synthesize annotation:
> 
> PortProduct "inputs" [PortProduct "input0" [PortName "value",PortName "valid"]]
> 
> but the port type:
> 
> Product "Spec.ValidInt" (Just ["value","valid"]) [Signed 64,Bool]
> 
> is not a product!
> 
> ```

I do wonder if that is perhaps a subtle bug related to your `Inputs` type. It feels like this should work, both for `newtype` and `data`. I’m going to create an issue for that; if it turns out I was mistaken and this is not supposed to work, we can always close the issue as invalid 🙂 .

Right, I should just try that. It works with `newtype`, so yeah, it’s a bug with `data`. You shouldn’t annotate the `newtype` itself with `PortProduct` though, just act like it isn’t there when writing the ports. This works:

```haskell
module Spec where

import Clash.Prelude
import Clash.Annotations.TopEntity

data ValidInt = ValidInt {
    value :: Int,
    valid :: Bool
} deriving (Generic, NFDataX)

newtype Inputs = Inputs {
    input0 :: ValidInt
} deriving (Generic, NFDataX)

machine :: HiddenClockResetEnable dom => Signal dom Inputs -> Signal dom Int
machine inputs = pure 42

topEntity :: Clock System -> Reset System -> Enable System ->
    Signal System Inputs -> Signal System Int
topEntity clk rst en inputs = exposeClockResetEnable (machine inputs) clk rst en
{-# ANN topEntity
  (Synthesize
    {
        t_name = "myModule",
        t_inputs = [
            PortName "clk",
            PortName "rst",
            PortName "en",
            PortProduct "input0" [
                PortName "value",
                PortName "valid"
            ]
        ],
        t_output = PortName "out"
    }) #-}

```

---

<div class="post-metadata">

**Author:** ![Bipinoli](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/bipinoli/32/25_2.png) [@Bipinoli](https://clash-lang.discourse.group/u/Bipinoli)\
**Post date:** [May 14, 2025, 4:24pm UTC](https://clash-lang.discourse.group/t/how-to-avoid-flattening-of-fields-in-record/79/5 "2025-05-14T16:24:12Z")

</div>

> [@DigitalBrains](#):
>
> ```auto
> module Spec where
> 
> import Clash.Prelude
> import Clash.Annotations.TopEntity
> 
> data ValidInt = ValidInt {
> value :: Int,
> valid :: Bool
> } deriving (Generic, NFDataX)
> 
> newtype Inputs = Inputs {
> input0 :: ValidInt
> } deriving (Generic, NFDataX)
> 
> machine :: HiddenClockResetEnable dom => Signal dom Inputs -> Signal dom Int
> machine inputs = pure 42
> 
> topEntity :: Clock System -> Reset System -> Enable System ->
> Signal System Inputs -> Signal System Int
> topEntity clk rst en inputs = exposeClockResetEnable (machine inputs) clk rst en
> {-# ANN topEntity
> (Synthesize
> {
> t_name = "myModule",
> t_inputs = [
> PortName "clk",
> PortName "rst",
> PortName "en",
> PortProduct "input0" [
> PortName "value",
> PortName "valid"
> ]
> ],
> t_output = PortName "out"
> }) #-}
> 
> ```

Perfect! This works like a charm.

Thank you very much for your regular help @DigitalBrains 🙏
