# SOLID cairo - OOP-like pattern

By [Only Dust](https://paragraph.com/@only-dust) · 2022-05-16

---

When I learn a new language, my first focus is to build [SOLID](https://en.wikipedia.org/wiki/SOLID) components while leveraging the feature of this new language.

In this article, I would like to present a new convention we at [OnlyDust](https://github.com/onlydustxyz) are adopting with regards to `cairo` development.

This new kind of architecture feels like object-oriented programming in a way and leverage several `cairo` features like:

*   implicit parameters
    
*   structs
    
*   namespaces
    

Following [OpenZeppelin’s recommendations](https://github.com/OpenZeppelin/cairo-contracts/blob/main/docs/Extensibility.md) about extensibility, we aims at building nice modules that can be re-usable and well tested.

A module is composed of:

*   `structs` to represent the current state of an object
    
*   `external functions` that are aimed at being imported (in smart contracts and unit tests)
    
*   `internal functions` that are meant to be kept private
    

As the memory is immutable in `cairo`, when interacting with an object, this object is usually being copied into a new version to be used. Using explicit parameters, this would result in providing the object both as input parameter and output parameter. Implicit parameters are better suited for this need as this is automatically done by the language.

This convention is especially useful when dealing with in-memory object when usage of storage is to be limited.

Let’s see how it looks:

    # person.cairo
    %lang starknet
    from starkware.cairo.common.math import assert_nn, assert_not_zero
    
    struct Wallet:
        member token : felt
        member balance : felt
    end
    
    # External functions
    namespace wallet_access:
        func create(token : felt) -> (wallet : Wallet):
            let wallet = Wallet(token, 0)
            internal.check_wallet{wallet=wallet}()
    
            return (wallet=wallet)
        end
    
        func increase_balance{wallet : Wallet}(amount : felt):
            let wallet = Wallet(wallet.token, wallet.balance + amount)
            return ()
        end
    end
    
    # Internal functions
    namespace internal:
        func check_wallet{wallet : Wallet}():
            with_attr error_message("Token cannot be 0"):
                assert_not_zero(wallet.token)
            end
            return ()
        end
    end
    

And here is the contract file that interact with it:

    # dex.cairo
    %lang starknet
    from src.wallet import Wallet, wallet_access
    
    @external
    func do_something(wallet : Wallet) -> (wallet : Wallet):
        with wallet:
            wallet_access.increase_balance(42)
            # Here wallet has been updated
        end
    
        return (wallet=wallet)
    end
    

Using this convention, it is actually possible to build [SOLID](https://en.wikipedia.org/wiki/SOLID) modules and interact with them.

It allows to build some design patterns on top of it like the iterator pattern presented [here](https://mirror.xyz/0xBa9E280B752B09eA866E9Cc0C8fE0fCef241B63c/ekwvUpolvVtZBVutk2D-hoxgCh0AtiK8QM_zfnvJ1fE).

---

*Originally published on [Only Dust](https://paragraph.com/@only-dust/solid-cairo-oop-like-pattern)*
