<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="376982" data-post-id="376982">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="18" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>One more thing: Hologram’s raison d’etre as I understand it is to be “Elixir on the client”. If you lean too heavily into a DSL, <em>even if that DSL is good</em> you are working against that mission. That could be a branding problem.</p>
</blockquote>
</aside>
<p>“Elixir on the client” is actually just stage one. The end goal is a cross-platform development platform with local-first auto-sync data store - Elixir all the way through. But I can’t market that yet because we’re not there.</p>
<p>Here’s the thing: Elixir in the browser alone doesn’t do much (unless you need serverless functions). What people actually want are modern frontend capabilities - reactivity, composability, state management, rich interactivity - without having to do all the plumbing like JS bundling, data serialization/transport, etc. That’s what this stage needs to deliver.</p>
<p>And I’m not aware of any full-stack web framework focused on local-first development. There are sync engines you can integrate, but no framework with local-first as a core, built-in capability. This is a blue ocean - new patterns will need to be designed anyway.</p>
<p>So the question isn’t “will this feel like pure Elixir?” but “will this enable developers to build modern web applications entirely in Elixir that they couldn’t easily build before?” The local-first capabilities combined with Elixir’s strengths could be genuinely novel - but only if we get the composability and reactivity patterns right first.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="376982" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-376982" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="376982"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="376983" data-post-id="376983">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="19" data-topic="73073" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>Can you explain in more detail what you mean with the call graph stuff? Is the call graph static? What happens if I try to make a function call dynamically?</p>
</blockquote>
</aside>
<p>The call graph is built statically at compile time by analyzing the IR. It determines which MFAs (module/function/arity) are reachable from each page, so only the necessary code gets transpiled to JavaScript for each bundle.</p>
<p>For dynamic calls like <code>apply(module, function, args)</code>, the compiler can track them when the module and function are known at compile time (static atoms). When they’re truly dynamic (variables), those calls fall back to the runtime interpreter on the client side.</p>
<p>I mentioned the call graph in the composability context because it could potentially be used for code analysis - like automatically determining what state a derived property depends on by analyzing which values it accesses. This could enable automatic reactivity tracking without manual declarations. But that’s just one possibility - it doesn’t have to be part of the solution.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="376983" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-376983" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="376983"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="377001" data-post-id="377001">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="bartblast" data-post="21" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>Hooks rely on hidden mutable state in React’s fiber tree. The render function <em>pretends</em> to be pure (<code>props → JSX</code>), but secretly accesses and mutates global framework state.</p>
</blockquote>
</aside>
<p>lol I was not trying to get into this again but since you specifically asked at the bottom of this reply I will try.</p>
<p>I think your perspective here is the wrong way around. Hooks are <a href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/" rel="noopener nofollow ugc">abusing global state to <em>emulate Algebraic Effects</em></a>. Algebraic Effects <a href="https://antelang.org/blog/why_effects/" rel="noopener nofollow ugc">are a <em>functional</em> construct</a>, and React is emulating them because React <em>wants</em> to be functional but is operating within the constraints of JavaScript.</p>
<p>It is possible (<em>by design</em>) to build hooks without global state if you have Algebraic Effects. All you need is to be able to jump somewhere defined up the call stack and then return to the current execution, i.e. a “resumable exception”. You do not actually need full-on global mutable state.</p>
<p>Elixir, like JS, lacks Algebraic Effects. But Elixir is still <em>closer</em> to being a pure functional language than JS. Even though Elixir and Erlang are not purely functional (very much by design), they are closer to the ideal that React is <em>designed for</em> than React itself! React would be <em>more idiomatic</em> if implemented in Elixir.</p>
<p>Just like React emulates Algebraic Effects, an “Elixir React” would do the same, either by passing messages or abusing the process dictionary. In other words, you would abuse global state the same way that JS does, but you must understand that it is <em>not</em> any less idiomatic here than it is in JS. In <em>both</em> cases the goal is to emulate a functional construct that both languages simply lack.</p>
<p>Also, I’m pretty sure you could emulate hooks even <em>without</em> Algebraic Effects by simply mutating the hooks on some struct (like the LiveView <code>socket</code>) and returning it. The only problem is that having to return the socket is more annoying, but this pattern is common in Elixir so maybe it’s fine!</p>
<aside class="quote no-group" data-username="bartblast" data-post="21" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>This interleaving is core to the hooks design, but it’s fundamentally incompatible with Hologram’s architecture where state is explicit data, not implicit framework-tracked position.</p>
</blockquote>
</aside>
<p>The purpose of the interleaving is to ensure that repeated executions of a declarative component refer to the same pieces of memory. Position was simply the best way they could come up with to ensure a particular line of code refers to a particular memory location. It’s analogous to how you allocate stack variables when you compile a function in e.g. C.</p>
<p>In Hologram, currently, you are instead assigning each variable an “explicit” key. This design is strictly <em>worse</em> because it does not compose, which is of course the topic of this thread. It’s not a <em>good</em> thing, it’s the thing you’re trying to get rid of.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377001" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-377001" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377001"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="377002" data-post-id="377002">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nikfp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nikfp/120/37207_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nikfp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/bartblast" rel="nofollow">@bartblast</a> after giving the stores API some thought, here’s where I landed. Keep in mind that this is naive and based on the public API in the Hologram docs. I’ve made some assumptions as well that I’ll do my best to outline as I go.</p>
<p>Commentary from anyone who’s interested is also welcome, even it it’s just to say “this is a terrible idea and the reasons are XYZ <img src="https://forum.elixirforum.com/images/emoji/apple/sweat_smile.png?v=15" title=":sweat_smile:" class="emoji" alt=":sweat_smile:" loading="lazy" width="20" height="20"> “</p>
<p>I would see the core of the stores starting with a struct looking roughly like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">%Store{
  id: "some-name", 
  root_component_cid: "component-name",
  implementation_module: MyApp.CounterStore
  state: %{
    value: 0
  }
}
</code></pre>
<p>State could be as simple as a single value, or nested structures to allow for complex requirements.</p>
<p>Stores could be built up from a core implementation to allow for customization like so:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyApp.CounterStore do
  use Hologram.Store

  # callbacks

  @impl true
  def init(initial_value) when is_integer(initial_value) do
    # Any processing needed to prepare the initial value passed in

    initial_value
  end

  @impl true
  handle_update(:increment, state) do
    %{value: value} = state

    updated_value = value + 1

    %{state | value: updated_value}
  end

  @impl true
  handle_update(:decrement, state) do
    %{value: value} = state

    updated_value = value - 1

    %{state | value: updated_value}
  end
end
</code></pre>
<p>This makes the assumption that there is an engine for storing stores, locating them as needed for updates and change tracking, and getting that to work in JS is built first.</p>
<p>Creating stores would take place in an <code>init</code> function of a stateful component, and the store itself would be treated like state. A utility function would build it, another function would allow binding to a value, and the store itself could be passed as a prop. I would assume that somewhere in here (that I haven’t listed) the <code>cid</code> of the root component would need to be attached to the <code>%Store{}</code> struct.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyApp.Counter do
  use Hologram.Component

  alias Hologram.Store

  def init(_props, component) do
    # returns a %Store{} struct, wired up as needed
    counter_store = Store.build(MyApp.CounterStore, 0)
    put_state(component, :counter, counter_store)
  end

  
  # bind the UI to the :value key in the store, or a nested value if appropriate
  # pass the store as a prop to ancestors
  def template do
    ~HOLO"""
    &lt;div&gt;
      &lt;p&gt;{Store.value(@counter, :value)}&lt;/p&gt;
      &lt;MyApp.CounterButtons counter_store={@counter} cid="buttons" /&gt;
    &lt;/div&gt;
    """
  end

end
</code></pre>
<p>Another utility function would allow for updates, and would know which module to dispatch the function to, based on the module name in the struct.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyApp.CounterButtons do
  use Hologram.Component

  alias Hologram.Store

  prop :counter_store, :store

  def template do
    ~HOLO"""
    &lt;button type="button" $click={action: :increment, target: @cid}&gt;increment&lt;/button&gt;
    &lt;button type="button" $click={action: :decrement, target: @cid}&gt;decrement&lt;/button&gt;
    """
  end

  def action(:increment, _params, component) do
    # The update function would delegate to the implementation of the store
    # store update functions could rely on pattern matching, 
    # though I'm not sure how well this would work when translated to JS. 
    store = Store.update(component.state.counter_store, :increment)

    put_state(component, :counter_store, store)
  end

  def action(:decrement, _params, component) do
    store = Store.update(component.state.counter_store, :decrement)

    put_state(component, :counter_store, store)
  end
end
</code></pre>
<p>A derived store would then follow a similar pattern, but only have an <code>init</code> function callback. Said function would take the a base store and a function to run to calculate the derivation each time the state of the base store changed. In a perfect world, the base store could be another derived store, allowing chaining derivations for more complex calculations. Similarly, allowing the base store to also be a list of several stores would allow deriving from several sources reactively.</p>
<p>Stores could then be “passed around” as needed, even through a context, and changing them through an explicit call in one place would trigger the reactivity chain for the store throughout rendered components. This would also decouple stores from the component state which would make them testable in isolation.</p>
<p>Let me know if I’m anywhere near the ballpark of what you had in mind.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377002" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-377002" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377002"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="377044" data-post-id="377044">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thank you for this detailed proposition <a class="mention" href="/u/nikfp" rel="nofollow">@nikfp</a>! I really appreciate you taking the time to think through the API <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>This is very similar to a broader concept I’ve been exploring around “Composables” or “Hooks” - something that manages state and behavior in a way that can be composed with components. Your store pattern is one manifestation of this idea, but the same principle could apply to other reusable behaviors.</p>
<p>The interesting question now is how these composables should integrate with components. I can see a few approaches:</p>
<ol>
<li>
<p><strong>Delegation</strong> (as you showed) - composables are explicit values passed around, with utility functions to interact with them</p>
</li>
<li>
<p><strong>Mixins</strong> - composables could inject state/actions directly into the component, so you’d reference merged values without the indirection</p>
</li>
<li>
<p><strong>Explicit namespacing</strong> - composables organize their state/actions/effects within namespaced keys, and the Component struct could be extended with additional fields (like effects, watchers, etc.) to hold composable-related concepts alongside the existing state</p>
</li>
</ol>
<p>Each has different trade-offs around explicitness vs. ergonomics.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377044" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-377044" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377044"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="377045" data-post-id="377045">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jam" data-post="7" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jam/48/36266_2.png" class="avatar"> jam:</div>
<blockquote>
<p><code>effect</code> (though I’ve never liked effect as a name, I’m not sure there’s a better alternative at this point).</p>
</blockquote>
</aside>
<p>Any ideas for alternative names?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377045" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-377045" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377045"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="377047" data-post-id="377047">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group quote-modified" data-username="garrison" data-post="24" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<aside class="quote no-group" data-username="bartblast" data-post="21" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>Hooks rely on hidden mutable state in React’s fiber tree. The render function <em>pretends</em> to be pure (<code>props → JSX</code>), but secretly accesses and mutates global framework state.</p>
</blockquote>
</aside>
<p>lol I was not trying to get into this again but since you specifically asked at the bottom of this reply I will try.</p>
<p>I think your perspective here is the wrong way around. Hooks are <a href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/" rel="noopener nofollow ugc">abusing global state to <em>emulate Algebraic Effects</em></a>. Algebraic Effects <a href="https://antelang.org/blog/why_effects/" rel="noopener nofollow ugc">are a <em>functional</em> construct</a>, and React is emulating them because React <em>wants</em> to be functional but is operating within the constraints of JavaScript.</p>
</blockquote>
</aside>
<p>That’s a bit of rhetorical judo there <img src="https://forum.elixirforum.com/images/emoji/apple/wink.png?v=15" title=":wink:" class="emoji" alt=":wink:" loading="lazy" width="20" height="20"> - we agree on the facts (hooks use hidden mutable state), but you’re reframing it as a necessary emulation of a functional pattern rather than a design issue. I see the argument, though I’m not entirely convinced that “abusing global state to emulate a functional construct” is necessarily more functional than having explicit state management. But I’m open to being wrong here.</p>
<aside class="quote no-group" data-username="garrison" data-post="24" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>Also, I’m pretty sure you could emulate hooks even <em>without</em> Algebraic Effects by simply mutating the hooks on some struct (like the LiveView <code>socket</code>) and returning it. The only problem is that having to return the socket is more annoying, but this pattern is common in Elixir so maybe it’s fine!</p>
</blockquote>
</aside>
<p>I’m genuinely interested in this. Would you be willing to sketch out how this could work in Elixir? Even pseudocode would be helpful. I’m trying to understand how the composability would work in practice with this approach.</p>
<aside class="quote no-group" data-username="garrison" data-post="24" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>In Hologram, currently, you are instead assigning each variable an “explicit” key. This design is strictly <em>worse</em> because it does not compose, which is of course the topic of this thread. It’s not a <em>good</em> thing, it’s the thing you’re trying to get rid of.</p>
</blockquote>
</aside>
<p>I completely understand this - and you’re right, that’s exactly why I started this thread. I don’t agree it’s necessarily a deal breaker (explicit keys work fine for many use cases), but I’m absolutely looking for more elegant solutions that would enable better composability.</p>
<p>So I’d love to hear your proposals. How would you approach composability in Hologram given Elixir’s constraints?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377047" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-377047" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377047"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="377050" data-post-id="377050">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nikfp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nikfp/120/37207_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nikfp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="bartblast" data-post="26" data-topic="73073">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<ul>
<li><strong>Mixins</strong> - composables could inject state/actions directly into the component, so you’d reference merged values without the indirection</li>
<li><strong>Explicit namespacing</strong> - composables organize their state/actions/effects within namespaced keys, and the Component struct could be extended with additional fields (like effects, watchers, etc.) to hold composable-related concepts alongside the existing state</li>
</ul>
</blockquote>
</aside>
<p>Do you have an idea forming of what these two approaches would look like?</p>
<p>For mixins as you described, I can see the dx being comfortable in simple cases, but I can also see that turning into a headache as things gain any complexity. Thinking about testing and debugging for example, you would have to grok the component <em>and everything that has been injected into it</em> to work on or diagnose anything.</p>
<p>Namespacing could be interesting. I was thinking in my example that the keys would relate to the root component and the store together, and the machinery behind isolating all of that would be largely abstracted. The usage would be explicit though. It sounds like you are thinking that the namespacing would be more explicit and the plumbing would be abstracted and hooked up during compile time. Which is fine, and that’s what some JS frameworks already do, so I don’t think the mental overhead would be hard to grasp for users.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377050" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-377050" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377050"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="377058" data-post-id="377058">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jam" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jam/120/36266_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jam
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks for putting this together. Feels a bit GenServer-y which is ok but I’m wondering if it could be even simpler.</p>
<p>What if <code>Hologram.Store</code> exposed these for the API:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Store.new(initial)
Store.get(store)
Store.set(store, value)
Store.update(store, fn value -&gt; ... end)
Store.watch(store, fn value -&gt; ... end)
Store.derive(store_or_list_of_stores, fn value(s) -&gt; ... end)
</code></pre>
<p>These could of course be wrapped in a module but wouldn’t have to be.</p>
<p>I’m not sure <code>Store.watch</code> is absolutely needed but could be handy. It would be equivalent to a svelte <code>.subscribe</code> to watch for changes.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377058" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-377058" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377058"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="377064" data-post-id="377064">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nikfp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nikfp/120/37207_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nikfp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think this looks great, especially for the less complex cases, which could be arguably more common.</p>
<p>My question for this is: how would you build from this to create instances of stores that restrict how they can be used? An example is having specific updates that can be called on a store instance, and anything else would be either a no-op or just not compile.</p>
<p>That’s kind of where I was going with the genserver / pattern match approach - restricted access to updates in particular, and the ability to validate initial state to confirm it provides what callers need to run. I’m biased because this pattern served me very well in svelte, but my view is the more complex state management gets, the more this kind of abstraction helps.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="377064" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/composability-patterns-for-hologram-looking-for-your-ideas/73073/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-377064" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="377064"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/73073/load_more?page=4">Load more posts (10 remaining)</a>
</div></template></turbo-stream>