Repository: Tochemey/goakt
Pull request #318 (2024-05-04 10:57:40)

refactor: code maintenance

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Tochemey/goakt/pull/318?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) Report
Attention: Patch coverage is `96.20253%` with `3 lines` in your changes are missing coverage. Please review.
> Project coverage is 86.75%. Comparing base [(`68e7922`)](https://app.codecov.io/gh/Tochemey/goakt/commit/68e792254e012bd0bd69eaf3740f8c6de193ce9a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) to head [(`e454fb8`)](https://app.codecov.io/gh/Tochemey/goakt/pull/318?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).

| [Files](https://app.codecov.io/gh/Tochemey/goakt/pull/318?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) | Patch % | Lines |
|---|---|---|
| [actors/actor\_system.go](https://app.codecov.io/gh/Tochemey/goakt/pull/318?src=pr&el=tree&filepath=actors%2Factor_system.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2FjdG9yX3N5c3RlbS5nbw==) | 92.59% | [2 Missing :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/318?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |
| [actors/reflection.go](https://app.codecov.io/gh/Tochemey/goakt/pull/318?src=pr&el=tree&filepath=actors%2Freflection.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3JlZmxlY3Rpb24uZ28=) | 91.66% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/318?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #318      +/-   ##
==========================================
+ Coverage   86.71%   86.75%   +0.04%     
==========================================
  Files          33       32       -1     
  Lines        3055     2998      -57     
==========================================
- Hits         2649     2601      -48     
+ Misses        295      285      -10     
- Partials      111      112       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Tochemey/goakt/pull/318?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).


Patch:
diff --git a/actors/actor_system.go b/actors/actor_system.go
index 49f5ea0..888765b 100644
--- a/actors/actor_system.go
+++ b/actors/actor_system.go
@@ -29,7 +29,6 @@ import (
 	"fmt"
 	"net"
 	"net/http"
-	"reflect"
 	"regexp"
 	"sync"
 	"time"
@@ -213,7 +212,7 @@ type actorSystem struct {
 	metricEnabled atomic.Bool
 	eventsChan    <-chan *cluster.Event
 
-	registry   registry
+	registry   types.Registry
 	reflection reflection
 }
 
@@ -249,7 +248,7 @@ func NewActorSystem(name string, opts ...Option) (ActorSystem, error) {
 		actorInitTimeout:    DefaultInitTimeout,
 		tracer:              noop.NewTracerProvider().Tracer(name),
 		eventsChan:          make(chan *cluster.Event, 1),
-		registry:            newRegistry(),
+		registry:            types.NewRegistry(),
 		clusterSyncStopSig:  make(chan types.Unit, 1),
 	}
 
@@ -382,7 +381,7 @@ func (x *actorSystem) InCluster() bool {
 
 // NumActors returns the total number of active actors in the system
 func (x *actorSystem) NumActors() uint64 {
-	return uint64(x.actors.Len())
+	return uint64(x.actors.len())
 }
 
 // Spawn creates or returns the instance of a given actor in the system
@@ -402,7 +401,7 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) (PID,
 		actorPath = NewPath(name, NewAddress(x.name, x.remotingHost, int(x.remotingPort)))
 	}
 
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if exist {
 		if pid.IsRunning() {
 			// return the existing instance
@@ -446,16 +445,14 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor) (PID,
 		return nil, err
 	}
 
-	x.actors.Set(pid)
-	x.registry.RegisterWithKey(name, actor)
-
+	x.actors.set(pid)
 	if x.clusterEnabled.Load() {
-		actorType := reflect.TypeOf(actor).Elem().Name()
+		actorType := types.RuntimeTypeOf(actor)
 		x.clusterChan <- &internalpb.WireActor{
 			ActorName:    name,
 			ActorAddress: actorPath.RemoteAddress(),
 			ActorPath:    actorPath.String(),
-			ActorType:    actorType,
+			ActorType:    actorType.Name(),
 		}
 	}
 
@@ -517,16 +514,14 @@ func (x *actorSystem) SpawnFromFunc(ctx context.Context, receiveFunc ReceiveFunc
 		return nil, err
 	}
 
-	x.actors.Set(pid)
-	x.registry.RegisterWithKey(actorID, actor)
-
+	x.actors.set(pid)
 	if x.clusterEnabled.Load() {
-		actorType := reflect.TypeOf(actor).Elem().Name()
+		actorType := types.RuntimeTypeOf(actor)
 		x.clusterChan <- &internalpb.WireActor{
 			ActorName:    actorID,
 			ActorAddress: actorPath.RemoteAddress(),
 			ActorPath:    actorPath.String(),
-			ActorType:    actorType,
+			ActorType:    actorType.Name(),
 		}
 	}
 
@@ -550,7 +545,7 @@ func (x *actorSystem) Kill(ctx context.Context, name string) error {
 		actorPath = NewPath(name, NewAddress(x.name, x.remotingHost, int(x.remotingPort)))
 	}
 
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if exist {
 		// stop the given actor. No need to record error in the span context
 		// because the shutdown method is taking care of that
@@ -580,13 +575,13 @@ func (x *actorSystem) ReSpawn(ctx context.Context, name string) (PID, error) {
 		actorPath = NewPath(name, NewAddress(x.name, x.remotingHost, int(x.remotingPort)))
 	}
 
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if exist {
 		if err := pid.Restart(spanCtx); err != nil {
 			return nil, errors.Wrapf(err, "failed to restart actor=%s", actorPath.String())
 		}
 
-		x.actors.Set(pid)
+		x.actors.set(pid)
 		return pid, nil
 	}
 
@@ -607,7 +602,7 @@ func (x *actorSystem) Name() string {
 func (x *actorSystem) Actors() []PID {
 	x.mutex.Lock()
 	defer x.mutex.Unlock()
-	return x.actors.List()
+	return x.actors.pids()
 }
 
 // PeerAddress returns the actor system address known in the cluster. That address is used by other nodes to communicate with the actor system.
@@ -639,7 +634,7 @@ func (x *actorSystem) ActorOf(ctx context.Context, actorName string) (addr *goak
 	}
 
 	// first check whether the actor exist locally
-	items := x.actors.List()
+	items := x.actors.pids()
 	for _, actorRef := range items {
 		if actorRef.ActorPath().Name() == actorName {
 			return actorRef.ActorPath().RemoteAddress(), actorRef, nil
@@ -690,7 +685,7 @@ func (x *actorSystem) LocalActor(actorName string) (PID, error) {
 		return nil, ErrActorSystemNotStarted
 	}
 
-	items := x.actors.List()
+	items := x.actors.pids()
 	for _, actorRef := range items {
 		if actorRef.ActorPath().Name() == actorName {
 			return actorRef, nil
@@ -826,7 +821,7 @@ func (x *actorSystem) Stop(ctx context.Context) error {
 	}
 
 	for _, actor := range x.Actors() {
-		x.actors.Delete(actor.ActorPath())
+		x.actors.delete(actor.ActorPath())
 		if err := actor.Shutdown(ctx); err != nil {
 			x.reset()
 			return err
@@ -847,7 +842,7 @@ func (x *actorSystem) RemoteLookup(_ context.Context, request *connect.Request[i
 	}
 
 	actorPath := NewPath(reqCopy.GetName(), NewAddress(x.Name(), reqCopy.GetHost(), int(reqCopy.GetPort())))
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if !exist {
 		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 		return nil, ErrAddressNotFound(actorPath.String())
@@ -891,7 +886,7 @@ func (x *actorSystem) RemoteAsk(ctx context.Context, stream *connect.BidiStream[
 		name := message.GetReceiver().GetName()
 		actorPath := NewPath(name, NewAddress(x.name, x.remotingHost, int(x.remotingPort)))
 
-		pid, exist := x.actors.Get(actorPath)
+		pid, exist := x.actors.get(actorPath)
 		if !exist {
 			logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 			return ErrAddressNotFound(actorPath.String())
@@ -951,7 +946,7 @@ func (x *actorSystem) RemoteTell(ctx context.Context, stream *connect.ClientStre
 					receiver.GetHost(),
 					int(receiver.GetPort())))
 
-			pid, exist := x.actors.Get(actorPath)
+			pid, exist := x.actors.get(actorPath)
 			if !exist {
 				logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 				return ErrAddressNotFound(actorPath.String())
@@ -983,7 +978,7 @@ func (x *actorSystem) RemoteReSpawn(ctx context.Context, request *connect.Reques
 	}
 
 	actorPath := NewPath(reqCopy.GetName(), NewAddress(x.Name(), reqCopy.GetHost(), int(reqCopy.GetPort())))
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if !exist {
 		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 		return nil, ErrAddressNotFound(actorPath.String())
@@ -993,7 +988,7 @@ func (x *actorSystem) RemoteReSpawn(ctx context.Context, request *connect.Reques
 		return nil, errors.Wrapf(err, "failed to restart actor=%s", actorPath.String())
 	}
 
-	x.actors.Set(pid)
+	x.actors.set(pid)
 	return connect.NewResponse(new(internalpb.RemoteReSpawnResponse)), nil
 }
 
@@ -1008,7 +1003,7 @@ func (x *actorSystem) RemoteStop(ctx context.Context, request *connect.Request[i
 	}
 
 	actorPath := NewPath(reqCopy.GetName(), NewAddress(x.Name(), reqCopy.GetHost(), int(reqCopy.GetPort())))
-	pid, exist := x.actors.Get(actorPath)
+	pid, exist := x.actors.get(actorPath)
 	if !exist {
 		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
 		return nil, ErrAddressNotFound(actorPath.String())
@@ -1018,7 +1013,7 @@ func (x *actorSystem) RemoteStop(ctx context.Context, request *connect.Request[i
 		return nil, errors.Wrapf(err, "failed to stop actor=%s", actorPath.String())
 	}
 
-	x.actors.Delete(actorPath)
+	x.actors.delete(actorPath)
 	return connect.NewResponse(new(internalpb.RemoteStopResponse)), nil
 }
 
@@ -1224,7 +1219,7 @@ func (x *actorSystem) housekeeper() {
 				for _, actor := range x.Actors() {
 					if !actor.IsRunning() {
 						x.logger.Infof("Removing actor=%s from system", actor.ActorPath().Name())
-						x.actors.Delete(actor.ActorPath())
+						x.actors.delete(actor.ActorPath())
 						if x.InCluster() {
 							if err := x.cluster.RemoveActor(context.Background(), actor.ActorPath().Name()); err != nil {
 								x.logger.Error(err.Error())
@@ -1282,10 +1277,10 @@ func (x *actorSystem) broadcastClusterEvents() {
 
 // clusterSync synchronizes the node' actors map to the cluster.
 func (x *actorSystem) clusterSync() {
-	typesMap := x.registry.List()
+	typesMap := x.actors.props()
 	if len(typesMap) != 0 {
 		x.logger.Info("syncing node actors map to the cluster...")
-		for actorID, actorType := range typesMap {
+		for actorID, prop := range typesMap {
 			actorPath := NewPath(actorID, NewAddress(x.name, "", -1))
 			if x.remotingEnabled.Load() {
 				actorPath = NewPath(actorID, NewAddress(x.name, x.remotingHost, int(x.remotingPort)))
@@ -1299,7 +1294,7 @@ func (x *actorSystem) clusterSync() {
 				ActorName:    actorID,
 				ActorAddress: actorPath.RemoteAddress(),
 				ActorPath:    actorPath.String(),
-				ActorType:    actorType.Name(),
+				ActorType:    prop.rtype.Name(),
 			}
 		}
 		x.logger.Info("node actors map successfully synced back to the cluster.")
diff --git a/actors/option.go b/actors/option.go
index 5a27c20..9cf26c7 100644
--- a/actors/option.go
+++ b/actors/option.go
@@ -114,11 +114,11 @@ func WithRemoting(host string, port int32) Option {
 }
 
 // WithClustering enables clustering on the actor system.
-func WithClustering(discoveryProvider discovery.Provider, partitionCount uint64, gossipPort, clusterPort int) Option {
+func WithClustering(provider discovery.Provider, partitionCount uint64, gossipPort, clusterPort int) Option {
 	return OptionFunc(func(a *actorSystem) {
 		a.clusterEnabled.Store(true)
 		a.partitionsCount = partitionCount
-		a.discoveryProvider = discoveryProvider
+		a.discoveryProvider = provider
 		a.clusterPort = clusterPort
 		a.gossipPort = gossipPort
 	})
diff --git a/actors/pid.go b/actors/pid.go
index b059c2f..1e47473 100644
--- a/actors/pid.go
+++ b/actors/pid.go
@@ -361,7 +361,7 @@ func (p *pid) Child(name string) (PID, error) {
 		return nil, ErrDead
 	}
 	childActorPath := NewPath(name, p.ActorPath().Address()).WithParent(p.ActorPath())
-	if cid, ok := p.children.Get(childActorPath); ok {
+	if cid, ok := p.children.get(childActorPath); ok {
 		p.childrenCount.Inc()
 		return cid, nil
 	}
@@ -371,7 +371,7 @@ func (p *pid) Child(name string) (PID, error) {
 // Children returns the list of all the children of the given actor that are still alive or an empty list
 func (p *pid) Children() []PID {
 	p.rwMutex.RLock()
-	children := p.children.List()
+	children := p.children.pids()
 	p.rwMutex.RUnlock()
 
 	cids := make([]PID, 0, len(children))
@@ -406,7 +406,7 @@ func (p *pid) Stop(ctx context.Context, cid PID) error {
 	children := p.children
 	p.rwMutex.RUnlock()
 
-	if cid, ok := children.Get(cid.ActorPath()); ok {
+	if cid, ok := children.get(cid.ActorPath()); ok {
 		desc := fmt.Sprintf("child.[%s] Shutdown", cid.ActorPath())
 		if err := cid.Shutdown(spanCtx); err != nil {
 			span.SetStatus(codes.Error, desc)
@@ -519,7 +519,7 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 	children := p.children
 	p.rwMutex.RUnlock()
 
-	if cid, ok := children.Get(childActorPath); ok {
+	if cid, ok := children.get(childActorPath); ok {
 		return cid, nil
 	}
 
@@ -562,7 +562,7 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 		return nil, err
 	}
 
-	p.children.Set(cid)
+	p.children.set(cid)
 	p.Watch(cid)
 
 	span.SetStatus(codes.Ok, "SpawnChild")
@@ -1226,7 +1226,7 @@ func (p *pid) freeChildren(ctx context.Context) {
 
 	for _, child := range p.Children() {
 		p.UnWatch(child)
-		p.children.Delete(child.ActorPath())
+		p.children.delete(child.ActorPath())
 		if err := child.Shutdown(ctx); err != nil {
 			p.logger.Panic(err)
 		}
@@ -1283,7 +1283,7 @@ func (p *pid) supervise(cid PID, watcher *watcher) {
 			switch p.supervisorStrategy {
 			case StopDirective:
 				p.UnWatch(cid)
-				p.children.Delete(cid.ActorPath())
+				p.children.delete(cid.ActorPath())
 				if err := cid.Shutdown(context.Background()); err != nil {
 					// this can enter into some infinite loop if we panic
 					// since we are just shutting down the actor we can just log the error
@@ -1298,7 +1298,7 @@ func (p *pid) supervise(cid PID, watcher *watcher) {
 				p.Watch(cid)
 			default:
 				p.UnWatch(cid)
-				p.children.Delete(cid.ActorPath())
+				p.children.delete(cid.ActorPath())
 				if err := cid.Shutdown(context.Background()); err != nil {
 					// this can enter into some infinite loop if we panic
 					// since we are just shutting down the actor we can just log the error
@@ -1458,11 +1458,11 @@ func (p *pid) removeChild(pid PID) {
 	}
 
 	path := pid.ActorPath()
-	if cid, ok := p.children.Get(path); ok {
+	if cid, ok := p.children.get(path); ok {
 		if cid.IsRunning() {
 			return
 		}
-		p.children.Delete(path)
+		p.children.delete(path)
 	}
 }
 
diff --git a/actors/pid_map.go b/actors/pid_map.go
index 770e342..434d8aa 100644
--- a/actors/pid_map.go
+++ b/actors/pid_map.go
@@ -25,61 +25,89 @@
 package actors
 
 import (
+	"reflect"
 	"sync"
 	"sync/atomic"
+
+	"github.com/tochemey/goakt/internal/types"
 )
 
+type prop struct {
+	pid   PID
+	rtype reflect.Type
+}
+
 type pidMap struct {
-	mu   *sync.RWMutex
-	size atomic.Int64
-	pids map[string]PID
+	mu       *sync.RWMutex
+	size     atomic.Int64
+	propsMap map[string]*prop
 }
 
 func newPIDMap(cap int) *pidMap {
 	return &pidMap{
-		mu:   &sync.RWMutex{},
-		pids: make(map[string]PID, cap),
+		mu:       &sync.RWMutex{},
+		propsMap: make(map[string]*prop, cap),
 	}
 }
 
-// Len returns the number of PIDs
-func (m *pidMap) Len() int {
+// len returns the number of PIDs
+func (m *pidMap) len() int {
 	return int(m.size.Load())
 }
 
-// Get retrieves a pid by its address
-func (m *pidMap) Get(path *Path) (pid PID, ok bool) {
+// get retrieves a pid by its address
+func (m *pidMap) get(path *Path) (pid PID, ok bool) {
 	m.mu.RLock()
-	defer m.mu.RUnlock()
-	pid, ok = m.pids[path.String()]
+	prop, ok := m.propsMap[path.String()]
+	if prop != nil {
+		pid = prop.pid
+		ok = true
+	}
+	m.mu.RUnlock()
 	return
 }
 
-// Set sets a pid in the map
-func (m *pidMap) Set(pid PID) {
+// set sets a pid in the map
+func (m *pidMap) set(pid PID) {
 	m.mu.Lock()
-	defer m.mu.Unlock()
 	if pid != nil {
-		m.pids[pid.ActorPath().String()] = pid
+		var rtype reflect.Type
+		handle := pid.ActorHandle()
+		if handle != nil {
+			rtype = types.RuntimeTypeOf(handle)
+		}
+
+		m.propsMap[pid.ActorPath().String()] = &prop{
+			pid:   pid,
+			rtype: rtype,
+		}
 		m.size.Add(1)
+		m.mu.Unlock()
 	}
 }
 
-// Delete removes a pid from the map
-func (m *pidMap) Delete(addr *Path) {
+// delete removes a pid from the map
+func (m *pidMap) delete(addr *Path) {
 	m.mu.Lock()
-	delete(m.pids, addr.String())
+	delete(m.propsMap, addr.String())
 	m.size.Add(-1)
 	m.mu.Unlock()
 }
 
-// List returns all actors as a slice
-func (m *pidMap) List() []PID {
+// pids returns all actors as a slice
+func (m *pidMap) pids() []PID {
 	m.mu.Lock()
 	var out []PID
-	for _, actor := range m.pids {
-		out = append(out, actor)
+	for _, prop := range m.propsMap {
+		out = append(out, prop.pid)
 	}
 	m.mu.Unlock()
 	return out
 }
+
+func (m *pidMap) props() map[string]*prop {
+	m.mu.Lock()
+	out := m.propsMap
+	m.mu.Unlock()
+	return out
+}
diff --git a/actors/reflection.go b/actors/reflection.go
index c4bf856..54d7069 100644
--- a/actors/reflection.go
+++ b/actors/reflection.go
@@ -24,50 +24,51 @@
 
 package actors
 
-import "reflect"
+import (
+	"reflect"
+
+	"github.com/tochemey/goakt/internal/types"
+)
 
 // reflection helps create an instance dynamically
 type reflection interface {
-	// ActorOf creates a new instance of Actor from its concrete type
-	ActorOf(rtype reflect.Type) (actor Actor, err error)
 	// ActorFrom creates a new instance of Actor from its FQN
 	ActorFrom(key string) (actor Actor, err error)
 }
 
 // reflectionImpl implements Reflection
 type reflectionImpl struct {
-	registry registry
+	registry types.Registry
 }
 
 // enforce compilation error
 var _ reflection = &reflectionImpl{}
 
 // newReflection creates an instance of Reflection
-func newReflection(registry registry) reflection {
+func newReflection(registry types.Registry) reflection {
 	return &reflectionImpl{registry: registry}
 }
 
-// ActorOf creates a new instance of an Actor
-func (r *reflectionImpl) ActorOf(rtype reflect.Type) (actor Actor, err error) {
-	iface := reflect.TypeOf((*Actor)(nil)).Elem()
-	isActor := rtype.Implements(iface) || reflect.PointerTo(rtype).Implements(iface)
+// ActorFrom creates a new instance of Actor from its FQN
+func (r *reflectionImpl) ActorFrom(key string) (actor Actor, err error) {
+	rtype, ok := r.registry.TypeOf(key)
+	if !ok {
+		return nil, ErrTypeNotRegistered
+	}
+	return r.actorOf(rtype)
+}
+
+func (r *reflectionImpl) actorOf(rtype reflect.Type) (actor Actor, err error) {
+	iActor := reflect.TypeOf((*Actor)(nil)).Elem()
+	isActor := rtype.Implements(iActor) || reflect.PointerTo(rtype).Implements(iActor)
 
 	if !isActor {
 		return nil, ErrInstanceNotAnActor
 	}
-	typVal := reflect.New(rtype)
 
-	if !typVal.IsValid() {
+	newInstance := reflect.New(rtype)
+	if !newInstance.IsValid() {
 		return nil, ErrInvalidInstance
 	}
-	return typVal.Interface().(Actor), nil
-}
-
-// ActorFrom creates a new instance of Actor from its FQN
-func (r *reflectionImpl) ActorFrom(key string) (actor Actor, err error) {
-	rtype, ok := r.registry.GetTypeOf(key)
-	if !ok {
-		return nil, ErrTypeNotRegistered
-	}
-	return r.ActorOf(rtype)
+	return newInstance.Interface().(Actor), nil
 }
diff --git a/actors/registry.go b/actors/registry.go
deleted file mode 100644
index abf23fd..0000000
--- a/actors/registry.go
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2022-2024 Tochemey
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package actors
-
-import (
-	"reflect"
-	"strings"
-	"sync"
-)
-
-// registry represents reflection registry for dynamic loading and creation of
-// actors at run-time
-type registry interface {
-	// Register an object
-	Register(v any)
-	// RegisterWithKey registers with an alias/key
-	RegisterWithKey(key string, v any)
-	// GetType returns the type of object,
-	GetType(v any) (reflect.Type, bool)
-	// GetTypeOf returns the type of an object name
-	GetTypeOf(name string) (reflect.Type, bool)
-	// GetTypeByKey returns the type of an object by key
-	GetTypeByKey(key string) (reflect.Type, bool)
-	// Deregister removes the registered object from the registry
-	Deregister(v any)
-	// DeregisterWithKey removes the registered object from the registry
-	DeregisterWithKey(key string)
-	// Exists return true when a given object is in the registry
-	Exists(v any) bool
-	// List returns the list of registered at any point in time
-	List() map[string]reflect.Type
-}
-
-// registryImpl implements Registry
-type registryImpl struct {
-	typesMap map[string]reflect.Type
-	mu       sync.Mutex
-}
-
-// enforce compilation error
-var _ registry = (*registryImpl)(nil)
-
-// newRegistry creates an instance of Registry
-func newRegistry() registry {
-	l := &registryImpl{
-		typesMap: make(map[string]reflect.Type),
-		mu:       sync.Mutex{},
-	}
-	return l
-}
-
-// Register an object with its fully qualified path
-func (r *registryImpl) Register(v any) {
-	var rtype reflect.Type
-	switch _type := v.(type) {
-	case reflect.Type:
-		rtype = _type
-	default:
-		rtype = reflect.TypeOf(v).Elem()
-	}
-
-	if _, exist := r.GetType(v); !exist {
-		r.mu.Lock()
-		r.typesMap[strings.ToLower(rtype.Name())] = rtype
-		r.mu.Unlock()
-	}
-}
-
-// Deregister removes the registered object from the registry
-func (r *registryImpl) Deregister(v any) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	delete(r.typesMap, nameOf(v))
-}
-
-// GetType returns the type of object
-func (r *registryImpl) GetType(v any) (reflect.Type, bool) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	t, ok := r.typesMap[nameOf(v)]
-	return t, ok
-}
-
-// GetTypeOf implements registry.
-func (r *registryImpl) GetTypeOf(name string) (reflect.Type, bool) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	t, ok := r.typesMap[strings.ToLower(name)]
-	return t, ok
-}
-
-// Exists implements Registry.
-func (r *registryImpl) Exists(v any) bool {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	_, ok := r.typesMap[nameOf(v)]
-	return ok
-}
-
-func nameOf(v any) string {
-	var rtype reflect.Type
-	switch _type := v.(type) {
-	case reflect.Type:
-		rtype = _type
-	default:
-		rtype = reflect.TypeOf(v).Elem()
-	}
-
-	return strings.ToLower(rtype.Name())
-}
-
-// List returns the list of registered at any point in time
-func (r *registryImpl) List() map[string]reflect.Type {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	out := make(map[string]reflect.Type, len(r.typesMap))
-	for key, val := range r.typesMap {
-		out[key] = val
-	}
-	return out
-}
-
-// DeregisterWithKey implements registry.
-func (r *registryImpl) DeregisterWithKey(key string) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	delete(r.typesMap, strings.ToLower(key))
-}
-
-// RegisterWithKey implements registry.
-func (r *registryImpl) RegisterWithKey(key string, v any) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	var rtype reflect.Type
-	switch _type := v.(type) {
-	case reflect.Type:
-		rtype = _type
-	default:
-		rtype = reflect.TypeOf(v).Elem()
-	}
-	r.typesMap[strings.ToLower(key)] = rtype
-}
-
-// GetTypeByKey returns the type of an object by key
-func (r *registryImpl) GetTypeByKey(key string) (reflect.Type, bool) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	t, ok := r.typesMap[strings.ToLower(key)]
-	return t, ok
-}
diff --git a/internal/types/registry.go b/internal/types/registry.go
new file mode 100644
index 0000000..9acb85a
--- /dev/null
+++ b/internal/types/registry.go
@@ -0,0 +1,132 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024 Tochemey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package types
+
+import (
+	"reflect"
+	"strings"
+	"sync"
+)
+
+// Map defines mapping between a type name and its runtime type
+type Map map[string]reflect.Type
+
+// Registry defines the types registry interface
+type Registry interface {
+	// Register an object
+	Register(v any)
+	// Deregister removes the registered object from the registry
+	Deregister(v any)
+	// Exists return true when a given object is in the registry
+	Exists(v any) bool
+	// TypesMap returns the list of registered at any point in time
+	TypesMap() Map
+	// Type returns the type of object
+	Type(v any) (reflect.Type, bool)
+	// TypeOf returns the type of an object name
+	TypeOf(name string) (reflect.Type, bool)
+}
+
+type registry struct {
+	typesMap Map
+	mu       *sync.RWMutex
+}
+
+var _ Registry = (*registry)(nil)
+
+// NewRegistry creates a new types registry
+func NewRegistry() Registry {
+	return &registry{
+		typesMap: Map{},
+		mu:       new(sync.RWMutex),
+	}
+}
+
+// Deregister removes the registered object from the registry
+func (r *registry) Deregister(v any) {
+	r.mu.Lock()
+	name, _ := nameAndTypeOf(v)
+	delete(r.typesMap, name)
+	r.mu.Unlock()
+}
+
+// Exists return true when a given object is in the registry
+func (r *registry) Exists(v any) bool {
+	r.mu.RLock()
+	name, _ := nameAndTypeOf(v)
+	_, ok := r.typesMap[name]
+	r.mu.RUnlock()
+	return ok
+}
+
+// TypesMap returns the list of registered at any point in time
+func (r *registry) TypesMap() Map {
+	r.mu.Lock()
+	out := r.typesMap
+	r.mu.Unlock()
+	return out
+}
+
+// Register an object
+func (r *registry) Register(v any) {
+	r.mu.Lock()
+	name, rtype := nameAndTypeOf(v)
+	r.typesMap[name] = rtype
+	r.mu.Unlock()
+}
+
+// Type returns the type of object
+func (r *registry) Type(v any) (reflect.Type, bool) {
+	r.mu.RLock()
+	name, _ := nameAndTypeOf(v)
+	out, ok := r.typesMap[name]
+	r.mu.RUnlock()
+	return out, ok
+}
+
+// TypeOf returns the type of an object name
+func (r *registry) TypeOf(name string) (reflect.Type, bool) {
+	r.mu.RLock()
+	out, ok := r.typesMap[strings.ToLower(name)]
+	r.mu.RUnlock()
+	return out, ok
+}
+
+func nameAndTypeOf(v any) (string, reflect.Type) {
+	rtype := RuntimeTypeOf(v)
+	return strings.ToLower(rtype.Name()), rtype
+}
+
+// RuntimeTypeOf returns the runtime type of an object
+func RuntimeTypeOf(v any) reflect.Type {
+	var rtype reflect.Type
+	switch _type := v.(type) {
+	case reflect.Type:
+		rtype = _type
+	default:
+		rtype = reflect.TypeOf(v).Elem()
+	}
+	return rtype
+}


Test patch:
diff --git a/actors/pid_map_test.go b/actors/pid_map_test.go
index 98ec4da..6e2d42c 100644
--- a/actors/pid_map_test.go
+++ b/actors/pid_map_test.go
@@ -39,21 +39,21 @@ func TestPIDMap(t *testing.T) {
 	// create a new PID map
 	pidMap := newPIDMap(5)
 	// add to the map
-	pidMap.Set(actorRef)
+	pidMap.set(actorRef)
 	// assert the length of the map
-	assert.EqualValues(t, 1, pidMap.Len())
+	assert.EqualValues(t, 1, pidMap.len())
 	// list the map
-	lst := pidMap.List()
+	lst := pidMap.pids()
 	assert.Len(t, lst, 1)
 	// fetch the inserted pid back
-	actual, ok := pidMap.Get(actorPath)
+	actual, ok := pidMap.get(actorPath)
 	assert.True(t, ok)
 	assert.NotNil(t, actual)
 	assert.IsType(t, new(pid), actual)
 	// remove the pid from the map
-	pidMap.Delete(actorPath)
+	pidMap.delete(actorPath)
 	// list the map
-	lst = pidMap.List()
+	lst = pidMap.pids()
 	assert.Len(t, lst, 0)
-	assert.EqualValues(t, 0, pidMap.Len())
+	assert.EqualValues(t, 0, pidMap.len())
 }
diff --git a/actors/reflection_test.go b/actors/reflection_test.go
index 9c31308..62251c9 100644
--- a/actors/reflection_test.go
+++ b/actors/reflection_test.go
@@ -30,12 +30,13 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	"github.com/tochemey/goakt/goaktpb"
+	"github.com/tochemey/goakt/internal/types"
 )
 
 func TestReflection(t *testing.T) {
 	t.Run("With ActorFrom", func(t *testing.T) {
 		t.Run("With happy path", func(t *testing.T) {
-			newRegistry := newRegistry()
+			newRegistry := types.NewRegistry()
 			// create an instance of an actor
 			actor := newTestActor()
 			// register the actor into the types registry
@@ -51,7 +52,7 @@ func TestReflection(t *testing.T) {
 			assert.IsType(t, new(testActor), actual)
 		})
 		t.Run("With actor not found", func(t *testing.T) {
-			newRegistry := newRegistry()
+			newRegistry := types.NewRegistry()
 			// create an instance of reflection
 			reflection := newReflection(newRegistry)
 			actual, err := reflection.ActorFrom("fakeActor")
@@ -59,7 +60,7 @@ func TestReflection(t *testing.T) {
 			assert.Nil(t, actual)
 		})
 		t.Run("With actor interface not implemented", func(t *testing.T) {
-			tl := newRegistry()
+			tl := types.NewRegistry()
 			nonActor := new(goaktpb.Address)
 			// register the actor into the types registry
 			tl.Register(nonActor)
@@ -70,46 +71,4 @@ func TestReflection(t *testing.T) {
 			assert.Nil(t, actual)
 		})
 	})
-
-	t.Run("With ActorOf", func(t *testing.T) {
-		t.Run("With happy path", func(t *testing.T) {
-			newRegistry := newRegistry()
-			// create an instance of an actor
-			actor := newTestActor()
-			// register the actor into the types registry
-			newRegistry.Register(actor)
-
-			// create an instance of reflection
-			reflection := newReflection(newRegistry)
-
-			rtype, ok := newRegistry.GetType(actor)
-			assert.True(t, ok)
-			assert.NotNil(t, rtype)
-
-			// create an instance of test actor from the string testActor
-			actual, err := reflection.ActorOf(rtype)
-
-			// perform some assertions
-			assert.NoError(t, err)
-			assert.NotNil(t, actual)
-			_, ok = actual.(*testActor)
-			assert.True(t, ok)
-			assert.IsType(t, new(testActor), actual)
-		})
-		t.Run("With unhappy path", func(t *testing.T) {
-			newRegistry := newRegistry()
-			// create an instance of reflection
-			reflection := newReflection(newRegistry)
-			nonActor := new(goaktpb.Address)
-			// register the actor into the types registry
-			newRegistry.Register(nonActor)
-
-			rtype, ok := newRegistry.GetType(nonActor)
-			assert.True(t, ok)
-			assert.NotNil(t, rtype)
-			actual, err := reflection.ActorOf(rtype)
-			assert.Error(t, err)
-			assert.Nil(t, actual)
-		})
-	})
 }
diff --git a/actors/registry_test.go b/internal/types/registry_test.go
similarity index 62%
rename from actors/registry_test.go
rename to internal/types/registry_test.go
index 25edffc..3fc7369 100644
--- a/actors/registry_test.go
+++ b/internal/types/registry_test.go
@@ -22,7 +22,7 @@
  * SOFTWARE.
  */
 
-package actors
+package types
 
 import (
 	"testing"
@@ -30,52 +30,33 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+type testStruct struct {
+}
+
 func TestRegistry(t *testing.T) {
 	t.Run("With new instance", func(t *testing.T) {
-		newRegistry := newRegistry()
+		newRegistry := NewRegistry()
 		var p any = newRegistry
-		_, ok := p.(registry)
+		_, ok := p.(Registry)
 		assert.True(t, ok)
 	})
 
 	t.Run("With registration", func(t *testing.T) {
-		registry := newRegistry()
+		registry := NewRegistry()
 		// create an instance of an object
-		actor := newTestActor()
+		obj := new(testStruct)
 		// register that actor
-		registry.Register(actor)
-		_, ok := registry.GetType(actor)
-		assert.True(t, ok)
-
-		_, ok = registry.GetTypeOf("testActor")
-		assert.True(t, ok)
-		assert.Len(t, registry.List(), 1)
-
-		registry.Deregister(actor)
-		assert.Len(t, registry.List(), 0)
-	})
-
-	t.Run("With registration/deregistration with key", func(t *testing.T) {
-		registry := newRegistry()
-
-		actor := newTestActor()
-		key := "key-1"
-		registry.RegisterWithKey(key, actor)
-		registry.Register(actor)
-
-		_, ok := registry.GetType(actor)
-		assert.True(t, ok)
-		_, ok = registry.GetTypeByKey(key)
+		registry.Register(obj)
+		_, ok := registry.Type(obj)
 		assert.True(t, ok)
 
-		_, ok = registry.GetTypeOf("testActor")
+		_, ok = registry.TypeOf("testStruct")
 		assert.True(t, ok)
-		assert.Len(t, registry.List(), 2)
+		assert.Len(t, registry.TypesMap(), 1)
 
-		registry.Deregister(actor)
-		assert.Len(t, registry.List(), 1)
+		assert.True(t, registry.Exists(obj))
 
-		registry.DeregisterWithKey(key)
-		assert.Empty(t, registry.List())
+		registry.Deregister(obj)
+		assert.Len(t, registry.TypesMap(), 0)
 	})
 }