Meta Programming
What is Metaprogramming ?
Metaprogramming is a computer programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyse, or transform other programs, and even modify itself, while running.[1][2] In some cases, this allows programmers to minimize the number of lines of code to express a solution, in turn reducing development time.[3] It also allows programs more flexibility to efficiently handle new situations with no recompiling.
Metaprogramming can be used to move computations from runtime to compile time, to generate code using compile time computations, and to enable self-modifying code. The ability of a programming language to be its own metalanguage allows reflective programming, and is termed reflection.[4] Reflection is a valuable language feature to facilitate metaprogramming.
Metaprogramming was popular in the 1970s and 1980s using list processing languages such as Lisp. Lisp machine hardware gained some notice in the 1980s, and enabled applications that could process code. They were often used for artificial intelligenceapplications. [Wikipedia-Metaprogramming]
Why we need Metaprogramming ?
- Code Reusability and Abstraction: Metaprogramming can help reduce code duplication by allowing you to write more generic and reusable code. For example, you can write a single piece of code that generates various classes or functions based on a set of parameters or a template.
- Dynamic Behavior: It enables programs to adapt their behavior at runtime. For example, you can use metaprogramming to implement custom serialization or deserialization logic, which can be useful for handling different data formats or adapting to changes in data structures.
- Reducing Boilerplate Code: Metaprogramming can automate the creation of boilerplate code, such as getters and setters, or implement design patterns like the Factory pattern. This reduces the amount of repetitive code you need to write and maintain.
- Domain-Specific Languages (DSLs): It allows you to create DSLs, which are specialized languages tailored to a specific problem domain. For instance, Ruby on Rails uses metaprogramming to provide a powerful DSL for building web applications.
- Code Generation: In some cases, metaprogramming is used to generate code based on certain rules or configurations. This can be especially useful in scenarios where the code needs to be generated dynamically, like in template engines or for integrating with different APIs.
- Enhanced Testing: Metaprogramming can be used to create mock objects, stubs, and other testing utilities that help in writing more effective and maintainable tests.
- Interfacing with Other Languages: It can be used to interface with other programming languages or systems, generating code that interacts with different APIs or systems based on changing requirements.
- Reflection and Introspection: Metaprogramming allows for reflection and introspection, meaning the ability to inspect and modify the structure and behavior of programs at runtime. This can be useful for debugging, logging, and other dynamic operations.
So what is the relationship between Swift and Metaprogramming
On the previous part of Design System we Declare all color and font Manually.
We can cut that step so we can focus on Logic that Declaring each type or kind of that stuff.
What is the Solution ?
The solution is we can Hand over that task to Swiftgen and Sourcery. With Swiftgen and Sourcery we can Auto generate All of that with just one Command.
Swiftgen
For installing and Usage you can check on their Github page. All you need is there. But I will give you my configuration for my Project.
## Note: all of the config entries below are just examples with placeholders. Be sure to edit and adjust to your needs when uncommenting.
## In case your config entries all use a common input/output parent directory, you can specify those here.
## Every input/output paths in the rest of the config will then be expressed relative to these.
## Those two top-level keys are optional and default to "." (the directory of the config file).
# input_dir: MyLib/Sources/
# output_dir: MyLib/Generated/
## Generate constants for your localized strings.
## Be sure that SwiftGen only parses ONE locale (typically Base.lproj, or en.lproj, or whichever your development region is); otherwise it will generate the same keys multiple times.
## SwiftGen will parse all `.strings` files found in that folder.
strings:
inputs:
- Project/Resources/en.lproj
outputs:
- templateName: structured-swift5
output: Project/Generated/Resources/Strings+Generated.swift
params:
enumName: LocalizableString
## Generate constants for your Assets Catalogs, including constants for images, colors, ARKit resources, etc.
## This example also shows how to provide additional parameters to your template to customize the output.
## - Especially the `forceProvidesNamespaces: true` param forces to create sub-namespace for each folder/group used in your Asset Catalogs, even the ones without "Provides Namespace". Without this param, SwiftGen only generates sub-namespaces for folders/groups which have the "Provides Namespace" box checked in the Inspector pane.
## - To know which params are supported for a template, use `swiftgen template doc xcassets swift5` to open the template documentation on GitHub.
xcassets:
inputs:
- Project/Resources/Assets.xcassets
outputs:
- templateName: swift5
params:
forceProvidesNamespaces: true
output: Project/Generated/Resources/XCAssets+Generated.swift
## Generate constants for your storyboards and XIBs.
## This one generates 2 output files, one containing the storyboard scenes, and another for the segues.
## (You can remove the segues entry if you don't use segues in your IB files).
## For `inputs` we can use "." here (aka "current directory", at least relative to `input_dir` = "MyLib/Sources"),
## and SwiftGen will recursively find all `*.storyboard` and `*.xib` files in there.
# ib:
# inputs:
# - .
# outputs:
# - templateName: scenes-swift5
# output: IB-Scenes+Generated.swift
# - templateName: segues-swift5
# output: IB-Segues+Generated.swift
## There are other parsers available for you to use depending on your needs, for example:
## - `fonts` (if you have custom ttf/ttc font files)
## - `coredata` (for CoreData models)
## - `json`, `yaml` and `plist` (to parse custom JSON/YAML/Plist files and generate code from their content)
## …
##
## For more info, use `swiftgen config doc` to open the full documentation on GitHub.
## https://github.com/SwiftGen/SwiftGen/tree/6.6.3/Documentation/
fonts:
inputs: Project/Resources/Fonts/Roboto
outputs:
templateName: swift5
output: Project/Generated/Resources/Fonts+Generated.swift
You can check swiftgen.yml above, I use Swiftgen to generate Localizable, Assets and Font so I dont need to type all Manually.
We group all generated file on the same folder, so we can distinct what file that auto generated or we create manually.
Project/Generated/Resources/
Next we will talk about Sourcery and Xcode file template so we can generate Clean Architecture base Module file and generate All Injection and Router code automatically.