diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,19 @@
 
 ## [Unreleased]
 
+## [0.9] - 2019-09-06
+### Added
+- Function `ORSet.getFieldObject`
+- Export `ORSetRep` constructor
+- Extend error reporting
+- `ORSet.removeObjectIf`
+- `ORSet.addFieldValue`
+- `ORSet.removeFieldValue`
+- `ORSet.removeFieldValueIf`
+
+### Changed
+- Renamed `getObject` to `readObject`
+
 ## [0.8] - 2019-08-10
 ### Added
 - Function `reduceState`
@@ -182,7 +195,8 @@
   - RON-Schema
   - RON-Schema TemplateHaskell code generator
 
-[Unreleased]: https://github.com/ff-notes/ron/compare/ron-rdt-0.8...HEAD
+[Unreleased]: https://github.com/ff-notes/ron/compare/ron-rdt-0.9...HEAD
+[0.9]: https://github.com/ff-notes/ron/compare/ron-rdt-0.8...ron-rdt-0.9
 [0.8]: https://github.com/ff-notes/ron/compare/ron-rdt-0.7...ron-rdt-0.8
 [0.7]: https://github.com/ff-notes/ron/compare/ron-rdt-0.6...ron-rdt-0.7
 [0.6]: https://github.com/ff-notes/ff/compare/v0.5...ron-rdt-0.6
diff --git a/lib/RON/Data.hs b/lib/RON/Data.hs
--- a/lib/RON/Data.hs
+++ b/lib/RON/Data.hs
@@ -50,11 +50,11 @@
 import           RON.Data.RGA (RgaRep)
 import           RON.Data.VersionVector (VersionVector)
 import           RON.Error (MonadE, throwErrorString)
-import           RON.Types (ClosedOp (..), Object (Object),
-                            ObjectFrame (ObjectFrame, frame, uuid), Op (..),
-                            StateChunk (..), StateFrame, UUID,
-                            WireChunk (Closed, Query, Value), WireFrame,
-                            WireReducedChunk (..),
+import           RON.Types (ClosedOp (..),
+                            ObjectFrame (ObjectFrame, frame, uuid),
+                            ObjectRef (ObjectRef), Op (..), StateChunk (..),
+                            StateFrame, UUID, WireChunk (Closed, Query, Value),
+                            WireFrame, WireReducedChunk (..),
                             WireStateChunk (WireStateChunk, stateBody, stateType))
 import           RON.UUID (pattern Zero)
 
@@ -190,19 +190,10 @@
         | otherwise = mof1
 
 -- | Run ObjectFrame action
-evalObjectState :: Monad m => ObjectFrame b -> ObjectStateT b m a -> m a
-evalObjectState ObjectFrame{uuid, frame} action =
-    evalStateT (runReaderT action $ Object uuid) frame
-
--- | Run ObjectFrame action, starting with an empty frame
-evalObjectState_ :: Monad m => StateT StateFrame m a -> m a
-evalObjectState_ action = evalStateT action mempty
-
--- | Run ObjectFrame action
 execObjectState
     :: Monad m => ObjectFrame b -> ObjectStateT b m a -> m (ObjectFrame b)
 execObjectState state@ObjectFrame{uuid, frame} action = do
-    frame' <- execStateT (runReaderT action $ Object uuid) frame
+    frame' <- execStateT (runReaderT action $ ObjectRef uuid) frame
     pure state{frame = frame'}
 
 -- | Run ObjectFrame action, starting with an empty frame
@@ -216,7 +207,7 @@
     -> ObjectStateT b m a
     -> m (a, ObjectFrame b)
 runObjectState state@ObjectFrame{uuid, frame} action =
-    runStateT (runReaderT action $ Object uuid) frame
+    runStateT (runReaderT action $ ObjectRef uuid) frame
     <&> \(a, frame') -> (a, state{frame = frame'})
 
 -- | Run ObjectFrame action, starting with an empty frame
@@ -225,6 +216,6 @@
 
 -- | Create new 'ObjectFrame' with an action
 newObjectFrameWith
-    :: Functor m => StateT StateFrame m (Object a) -> m (ObjectFrame a)
+    :: Functor m => StateT StateFrame m (ObjectRef a) -> m (ObjectFrame a)
 newObjectFrameWith action =
-    runObjectState_ action <&> \(Object uuid, frame) -> ObjectFrame{uuid, frame}
+    runObjectState_ action <&> \(ObjectRef uuid, frame) -> ObjectFrame{uuid, frame}
diff --git a/lib/RON/Data/Internal.hs b/lib/RON/Data/Internal.hs
--- a/lib/RON/Data/Internal.hs
+++ b/lib/RON/Data/Internal.hs
@@ -24,6 +24,8 @@
     advanceToObject,
     eqPayload,
     eqRef,
+    evalObjectState,
+    evalObjectState_,
     getObjectState,
     getObjectStateChunk,
     modifyObjectStateChunk,
@@ -59,8 +61,9 @@
                             liftMaybe)
 import           RON.Event (ReplicaClock, advanceToUuid)
 import           RON.Semilattice (BoundedSemilattice)
-import           RON.Types (Atom (AInteger, AString, AUuid), Object (Object),
+import           RON.Types (Atom (AInteger, AString, AUuid),
                             ObjectFrame (ObjectFrame, frame, uuid),
+                            ObjectRef (ObjectRef),
                             Op (Op, opId, payload, refId), Payload,
                             StateChunk (StateChunk), StateFrame, UUID (UUID),
                             WireChunk,
@@ -178,9 +181,9 @@
 objectEncoding :: ReplicatedAsObject a => Encoding a
 objectEncoding = Encoding
     { encodingNewRon = \a -> do
-        Object uuid <- newObject a
+        ObjectRef uuid <- newObject a
         pure [AUuid uuid]
-    , encodingFromRon = objectFromRon $ runReaderT getObject
+    , encodingFromRon = objectFromRon $ runReaderT readObject
     }
 
 -- | Standard implementation of 'Replicated' for 'ReplicatedAsPayload' types.
@@ -243,30 +246,30 @@
     type Rep a
 
     -- | Encode data. Write frame and return id.
-    newObject :: (ReplicaClock m, MonadState StateFrame m) => a -> m (Object a)
+    newObject
+        :: (ReplicaClock m, MonadState StateFrame m) => a -> m (ObjectRef a)
 
     -- | Decode data
-    getObject :: (MonadE m, MonadObjectState a m) => m a
-
-    -- | Counterpart of 'mempty', but without an explicit 'Semigroup'
-    -- rempty :: a
+    readObject :: (MonadE m, MonadObjectState a m) => m a
 
-objectFromRon :: MonadE m => (Object a -> m a) -> Payload -> m a
-objectFromRon handler atoms = case atoms of
-    [AUuid uuid] -> handler $ Object uuid
-    _            -> throwError "Expected object UUID"
+objectFromRon :: MonadE m => (ObjectRef a -> m a) -> Payload -> m a
+objectFromRon handler atoms =
+    errorContext "objectFromRon" $
+        case atoms of
+            [AUuid uuid] -> handler $ ObjectRef uuid
+            _            -> throwError "Expected object UUID"
 
 -- | Create new 'ObjectFrame' from a value
 newObjectFrame
     :: (ReplicatedAsObject a, ReplicaClock m) => a -> m (ObjectFrame a)
 newObjectFrame a = do
-    (Object uuid, frame) <- runStateT (newObject a) mempty
+    (ObjectRef uuid, frame) <- runStateT (newObject a) mempty
     pure $ ObjectFrame{uuid, frame}
 
 getObjectStateChunk
     :: forall a m . (MonadE m, MonadObjectState a m) => m (StateChunk (Rep a))
 getObjectStateChunk = do
-    Object uuid <- ask
+    ObjectRef uuid <- ask
     frame <- get
     WireStateChunk{stateType, stateBody} <-
         liftMaybe "no such object in chunk" $ Map.lookup uuid frame
@@ -284,7 +287,7 @@
     => (StateChunk (Rep a) -> m (b, StateChunk (Rep a))) -> m b
 modifyObjectStateChunk f = do
     advanceToObject
-    Object uuid <- ask
+    ObjectRef uuid <- ask
     chunk <- getObjectStateChunk
     (a, StateChunk chunk') <- f chunk
     modify' $
@@ -299,8 +302,8 @@
     chunk' <- f chunk
     pure ((), chunk')
 
-eqRef :: Object a -> Payload -> Bool
-eqRef (Object uuid) atoms = case atoms of
+eqRef :: ObjectRef a -> Payload -> Bool
+eqRef (ObjectRef uuid) atoms = case atoms of
     [AUuid ref] -> uuid == ref
     _           -> False
 
@@ -325,14 +328,14 @@
         [AFalse] -> pure False
         _        -> throwError "Expected single UUID `true` or `false`"
 
-type ObjectStateT b m a = ReaderT (Object b) (StateT StateFrame m) a
+type ObjectStateT b m a = ReaderT (ObjectRef b) (StateT StateFrame m) a
 
 type MonadObjectState a m =
-    (MonadReader (Object a) m, MonadState StateFrame m, Reducible (Rep a))
+    (MonadReader (ObjectRef a) m, MonadState StateFrame m, Reducible (Rep a))
 
 advanceToObject :: (MonadE m, MonadObjectState a m, ReplicaClock m) => m ()
 advanceToObject = do
-    Object uuid <- ask
+    ObjectRef uuid <- ask
     StateChunk chunk <- getObjectStateChunk
     advanceToUuid $
         maximumDef
@@ -355,13 +358,13 @@
 reduceObjectStates
     :: forall a m
     . (MonadE m, MonadState StateFrame m, ReplicatedAsObject a)
-    => NonEmpty (Object a) -> m (Object a)
+    => NonEmpty (ObjectRef a) -> m (ObjectRef a)
 reduceObjectStates (obj :| objs) = do
     c :| cs <- for (obj :| objs) $ runReaderT getObjectStateChunk
     let chunk = foldl' (reduceState @(Rep a)) c cs
-        oid = minimum [i | Object i <- obj:objs]
+        oid = minimum [i | ObjectRef i <- obj:objs]
     modify' $ Map.insert oid $ wireStateChunk chunk
-    pure $ Object oid
+    pure $ ObjectRef oid
 
 rconcat
     :: forall a m
@@ -369,7 +372,7 @@
     => NonEmpty UUID -> m a
 rconcat uuids =
     errorContext "rconcat" $ do
-        Object ref <- reduceObjectStates @a $ Object <$> uuids
+        ObjectRef ref <- reduceObjectStates @a $ ObjectRef <$> uuids
         fromRon [AUuid ref]
 
 tryFromRon
@@ -404,3 +407,19 @@
 wireStateChunk :: forall rep . Reducible rep => StateChunk rep -> WireStateChunk
 wireStateChunk (StateChunk stateBody) =
     WireStateChunk{stateType = reducibleOpType @rep, stateBody}
+
+-- | Run ObjectFrame action
+evalObjectState :: Monad m => ObjectFrame b -> ObjectStateT b m a -> m a
+evalObjectState ObjectFrame{uuid, frame} action =
+    evalStateT (runReaderT action $ ObjectRef uuid) frame
+
+-- | Run ObjectFrame action, starting with an empty frame
+evalObjectState_ :: Monad m => StateT StateFrame m a -> m a
+evalObjectState_ action = evalStateT action mempty
+
+instance Replicated (ObjectRef a) where
+    encoding = payloadEncoding
+
+instance ReplicatedAsPayload (ObjectRef a) where
+    toPayload (ObjectRef uuid) = toPayload uuid
+    fromPayload = fmap ObjectRef . fromPayload
diff --git a/lib/RON/Data/LWW.hs b/lib/RON/Data/LWW.hs
--- a/lib/RON/Data/LWW.hs
+++ b/lib/RON/Data/LWW.hs
@@ -34,7 +34,7 @@
 import           RON.Error (MonadE, errorContext)
 import           RON.Event (ReplicaClock, getEventUuid)
 import           RON.Semilattice (Semilattice)
-import           RON.Types (Atom (AUuid), Object (Object),
+import           RON.Types (Atom (AUuid), ObjectRef (ObjectRef),
                             Op (Op, opId, payload, refId),
                             StateChunk (StateChunk), StateFrame, UUID,
                             WireStateChunk (WireStateChunk, stateBody, stateType))
@@ -144,4 +144,4 @@
         fieldObjectId <- errorContext "inner object" $ case payload of
             [AUuid oid] -> pure oid
             _           -> throwError "Expected object UUID"
-        lift $ runReaderT innerModifier $ Object fieldObjectId
+        lift $ runReaderT innerModifier $ ObjectRef fieldObjectId
diff --git a/lib/RON/Data/ORSet.hs b/lib/RON/Data/ORSet.hs
--- a/lib/RON/Data/ORSet.hs
+++ b/lib/RON/Data/ORSet.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ApplicativeDo #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NamedFieldPuns #-}
@@ -13,17 +14,22 @@
     ORSet (..),
     ORSetItem (..),
     ORSetMap,
-    ORSetRep,
+    ORSetRep (..),
     addRef,
     addValue,
     findAnyAlive,
     findAnyAlive',
+    removeObjectIf,
     removeRef,
     removeValue,
     zoomItem,
     -- * struct_set
+    addFieldValue,
     assignField,
+    getFieldObject,
     newStruct,
+    removeFieldValue,
+    removeFieldValueIf,
     viewField,
     viewFieldLWW,
     viewFieldMax,
@@ -38,18 +44,20 @@
 
 import           RON.Data.Internal (MonadObjectState, ObjectStateT, Reducible,
                                     Rep, Replicated (encoding),
-                                    ReplicatedAsObject, ReplicatedAsPayload,
-                                    eqPayload, eqRef, fromPayload, fromRon,
-                                    getObject, getObjectState,
-                                    getObjectStateChunk,
+                                    ReplicatedAsObject,
+                                    ReplicatedAsPayload (fromPayload),
+                                    eqPayload, eqRef, evalObjectState, fromRon,
+                                    getObjectState, getObjectStateChunk,
                                     modifyObjectStateChunk_, newObject, newRon,
-                                    objectEncoding, rconcat, reduceObjectStates,
-                                    reducibleOpType, stateFromChunk,
-                                    stateToChunk)
+                                    objectEncoding, rconcat, readObject,
+                                    reduceObjectStates, reducibleOpType,
+                                    stateFromChunk, stateToChunk)
 import           RON.Error (MonadE, errorContext, throwErrorText)
 import           RON.Event (ReplicaClock, getEventUuid)
 import           RON.Semilattice (Semilattice)
-import           RON.Types (Atom (AUuid), Object (Object),
+import           RON.Types (Atom (AUuid),
+                            ObjectFrame (ObjectFrame, frame, uuid),
+                            ObjectRef (ObjectRef),
                             Op (Op, opId, payload, refId), Payload,
                             StateChunk (StateChunk), StateFrame, UUID,
                             WireStateChunk (WireStateChunk, stateBody, stateType))
@@ -122,9 +130,9 @@
             pure $ Op event Zero payload
         oid <- getEventUuid
         modify' $ Map.insert oid $ wireStateChunk ops
-        pure $ Object oid
+        pure $ ObjectRef oid
 
-    getObject = do
+    readObject = do
         StateChunk ops <- getObjectStateChunk
         mItems <- for ops $ \Op{refId, payload} -> case refId of
             Zero -> do
@@ -133,8 +141,6 @@
             _    -> pure Nothing
         pure . ORSet $ catMaybes mItems
 
-    -- rempty = ORSet []
-
 -- | XXX Internal. Common implementation of 'addValue' and 'addRef'.
 commonAdd :: (MonadE m, MonadObjectState a m, ReplicaClock m) => Payload -> m ()
 commonAdd payload =
@@ -152,21 +158,24 @@
 
 addRef
     :: (ReplicaClock m, MonadE m, MonadObjectState (ORSet a) m)
-    => Object a -> m ()
-addRef (Object itemUuid) = commonAdd [AUuid itemUuid]
+    => ObjectRef a -> m ()
+addRef (ObjectRef itemUuid) = commonAdd [AUuid itemUuid]
 
 -- | XXX Internal. Common implementation of 'removeValue' and 'removeRef'.
 commonRemove
     :: (MonadE m, ReplicaClock m, MonadObjectState (ORSet a) m)
-    => (Payload -> Bool) -> m ()
+    => (Payload -> m Bool) -> m ()
 commonRemove isTarget =
     modifyObjectStateChunk_ $ \(StateChunk chunk) -> do
         let state0@(ORSetRep opMap) = stateFromChunk chunk
-        let targetEvents =
-                [ op
-                | op@Op{refId = Zero, payload} <- toList opMap
-                , isTarget payload
-                ]
+        targetEvents <-
+            fmap catMaybes
+            $ for (toList opMap) $ \op@Op{refId, payload} ->
+                case refId of
+                    Zero -> do
+                        t <- isTarget payload
+                        pure $ if t then Just op else Nothing
+                    _ -> pure Nothing
         StateChunk <$>
             case targetEvents of
                 [] -> pure chunk
@@ -179,19 +188,77 @@
                     let state' = state0 <> stateFromChunk patch
                     pure $ stateToChunk state'
 
+removeObjectIf
+    :: (MonadE m, ReplicaClock m, MonadObjectState (ORSet a) m)
+    => ObjectStateT a m Bool -> m ()
+removeObjectIf isTarget = commonRemove $ \case
+    AUuid uuid' : _ -> do
+        frame <- get
+        evalObjectState ObjectFrame{uuid = uuid', frame} isTarget
+    _ -> pure False
+
 -- | Remove an atomic value from the OR-Set
 removeValue
     ::  ( ReplicatedAsPayload a
         , MonadE m, ReplicaClock m, MonadObjectState (ORSet a) m
         )
     => a -> m ()
-removeValue = commonRemove . eqPayload
+removeValue v = commonRemove $ pure . eqPayload v
 
+-- | Remove from a field all values that equal to the specified value.
+removeFieldValue
+    ::  ( MonadE m
+        , MonadObjectState struct m
+        , ReplicaClock m
+        , ReplicatedAsPayload a
+        )
+    => UUID -- ^ Field name
+    -> a -- ^ Value
+    -> m ()
+removeFieldValue field value =
+    removeFieldValueIfP field $ pure . eqPayload value
+
+-- | Remove from a field all values that obey the predicate.
+removeFieldValueIf
+    ::  ( MonadE m
+        , MonadObjectState struct m
+        , ReplicaClock m
+        , ReplicatedAsPayload a
+        )
+    => UUID -- ^ Field name
+    -> (a -> m Bool)
+    -> m ()
+removeFieldValueIf field isTarget =
+    removeFieldValueIfP field $ \valuePayload -> do
+        value <- fromPayload valuePayload
+        isTarget value
+
+-- | Remove from a field all payloads that obey the predicate.
+removeFieldValueIfP
+    :: (MonadE m, MonadObjectState struct m, ReplicaClock m)
+    => UUID -- ^ Field name
+    -> (Payload -> m Bool)
+    -> m ()
+removeFieldValueIfP field isTarget =
+    modifyObjectStateChunk_ $ \(StateChunk stateBody) -> do
+        (observedOps, stateBody1) <-
+            partitionM isFieldAliveAndSameValue stateBody
+        removeOps <- for observedOps $ \op@Op{opId = observedEvent} -> do
+            tombstone <- getEventUuid  -- TODO(2019-07-10, cblp) sequential
+            pure op{opId = tombstone, refId = observedEvent}
+        let stateBody2 = stateBody1 ++ removeOps
+        pure $ StateChunk stateBody2
+  where
+    isFieldAliveAndSameValue = \case
+        Op{refId = Zero, payload = AUuid field' : valuePayload}
+            | field' == field -> isTarget valuePayload
+        _ -> pure False
+
 -- | Remove an object reference from the OR-Set
 removeRef
     :: (MonadE m, ReplicaClock m, MonadObjectState (ORSet a) m)
-    => Object a -> m ()
-removeRef = commonRemove . eqRef
+    => ObjectRef a -> m ()
+removeRef r = commonRemove $ pure . eqRef r
 
 -- | Reference to an item inside an 'ORSet'.
 newtype ORSetItem a = ORSetItem UUID
@@ -211,7 +278,7 @@
         Just Op{payload} -> case payload of
             [AUuid itemValueRef] -> pure itemValueRef
             _ -> throwErrorText "item payload is not an object ref"
-    lift $ runReaderT innerModifier $ Object itemValueRef
+    lift $ runReaderT innerModifier $ ObjectRef itemValueRef
 
 -- | Find any alive item. If no alive item found, return 'Nothing'.
 findAnyAlive
@@ -234,7 +301,8 @@
 
 type ORSetMap k v = ORSet (k, v)
 
--- | Assign a value to a field
+-- | Assign a value to a field, deleting all previous (observed) values.
+-- Assignment of 'Nothing' just deletes all values.
 assignField
     :: (Replicated a, ReplicaClock m, MonadE m, MonadObjectState struct m)
     => UUID     -- ^ Field name
@@ -242,19 +310,38 @@
     -> m ()
 assignField field mvalue =
     modifyObjectStateChunk_ $ \(StateChunk stateBody) -> do
+        addOp <- case mvalue of
+            Just value -> do
+                event <- getEventUuid
+                valuePayload <- newRon value
+                pure $ Just Op
+                    { opId = event
+                    , refId = Zero
+                    , payload = AUuid field : valuePayload
+                    }
+            Nothing -> pure Nothing
+        let (observedOps, stateBody1) = partition (isAliveField field) stateBody
+        removeOps <- for observedOps $ \op@Op{opId = observedEvent} -> do
+            tombstone <- getEventUuid  -- TODO(2019-07-10, cblp) sequential
+            pure op{opId = tombstone, refId = observedEvent}
+        let stateBody2 = stateBody1 ++ toList addOp ++ removeOps
+        pure $ StateChunk stateBody2
+
+addFieldValue
+    :: (Replicated a, ReplicaClock m, MonadE m, MonadObjectState struct m)
+    => UUID  -- ^ Field name
+    -> a     -- ^ Value
+    -> m ()
+addFieldValue field value =
+    modifyObjectStateChunk_ $ \(StateChunk stateBody) -> do
         event <- getEventUuid
-        valuePayload <- maybe (pure []) newRon mvalue
+        valuePayload <- newRon value
         let addOp = Op
                 { opId = event
                 , refId = Zero
                 , payload = AUuid field : valuePayload
                 }
-        let (observedOps, stateBody1) = partition (isAliveField field) stateBody
-        removeOps <- for observedOps $ \op@Op{opId = observedEvent} -> do
-            tombstone <- getEventUuid  -- TODO(2019-07-10, cblp) sequential
-            pure op{opId = tombstone, refId = observedEvent}
-        let stateBody2 = sortOn opId $ addOp : removeOps ++ stateBody1
-        pure $ StateChunk stateBody2
+        pure $ StateChunk $ stateBody ++ [addOp]
 
 isAliveField :: UUID -> Op -> Bool
 isAliveField field = \case
@@ -281,6 +368,20 @@
     , field' == field
     ]
 
+-- | Find object field, merge all versions, return 'Nothing' if no versions
+getFieldObject
+    :: (MonadE m, MonadObjectState struct m, ReplicatedAsObject a)
+    => UUID                 -- ^ Field name
+    -> m (Maybe (ObjectRef a))
+getFieldObject field =
+    errorContext "ORSet.getFieldObject" $ do
+        StateChunk ops <- getObjectStateChunk
+        let payloads = filterAliveFieldPayloads field ops
+            refs = [ref | AUuid ref : _ <- payloads]
+        case refs of
+            []   -> pure Nothing
+            p:ps -> fmap Just $ reduceObjectStates $ fmap ObjectRef $ p :| ps
+
 -- | Decode field value, merge all versions, return 'Nothing' if no versions
 viewField
     :: (MonadE m, MonadState StateFrame m, ReplicatedAsObject a)
@@ -358,29 +459,35 @@
     ->  ObjectStateT field  m a  -- ^ Inner object modifier
     ->  ObjectStateT struct m a
 zoomFieldObject field innerModifier =
-    errorContext ("ORSet.zoomFieldObject" <> show field) $ do
+    errorContext ("ORSet.zoomFieldObject " <> show field) $ do
         (StateChunk stateBody) <- getObjectStateChunk
         let objectIds =
                 [ objectId
                 | AUuid objectId : _ <- filterAliveFieldPayloads field stateBody
                 ]
         object <- case objectIds of
-            []       -> Object <$> getEventUuid  -- create empty object
-            oid:oids -> reduceObjectStates @field $ fmap Object $ oid :| oids
+            []       -> ObjectRef <$> getEventUuid  -- create empty object
+            oid:oids -> reduceObjectStates @field $ fmap ObjectRef $ oid :| oids
         lift $ runReaderT innerModifier object
 
 -- | Create an ORSet object from a list of named fields.
 newStruct
     :: (MonadState StateFrame m, ReplicaClock m)
-    => [(UUID, Maybe (Instance Replicated))] -> m UUID
+    => [(UUID, Instance Replicated)] -> m UUID
 newStruct fields = do
     objectId <- getEventUuid
     stateBody <-
-        for fields $ \(name, mvalue) -> do
+        for fields $ \(name, Instance value) -> do
             opId <- getEventUuid -- TODO(2019-07-12, cblp, #15) sequential uuids
-            valuePayload <- case mvalue of
-                Just (Instance value) -> newRon value
-                Nothing               -> pure []
+            valuePayload <- newRon value
             pure Op{opId, refId = Zero, payload = AUuid name : valuePayload}
     modify' $ Map.insert objectId $ wireStateChunk stateBody
     pure objectId
+
+partitionM :: Applicative m => (a -> m Bool) -> [a] -> m ([a], [a])
+partitionM f = \case
+    [] -> pure ([], [])
+    x:xs -> do
+        res <- f x
+        (as, bs) <- partitionM f xs
+        pure ([x | res] ++ as, [x | not res] ++ bs)
diff --git a/lib/RON/Data/RGA.hs b/lib/RON/Data/RGA.hs
--- a/lib/RON/Data/RGA.hs
+++ b/lib/RON/Data/RGA.hs
@@ -45,16 +45,17 @@
                                     ReducedChunk (ReducedChunk, rcBody, rcRef),
                                     Reducible, Rep, Replicated (encoding),
                                     ReplicatedAsObject, ReplicatedAsPayload,
-                                    Unapplied, applyPatches, fromRon, getObject,
+                                    Unapplied, applyPatches, fromRon,
                                     getObjectStateChunk,
                                     modifyObjectStateChunk_, newObject, newRon,
-                                    objectEncoding, reduceUnappliedPatches,
-                                    reducibleOpType, stateFromChunk,
-                                    stateToChunk, toPayload)
+                                    objectEncoding, readObject,
+                                    reduceUnappliedPatches, reducibleOpType,
+                                    stateFromChunk, stateToChunk, toPayload)
 import           RON.Error (MonadE, errorContext, throwErrorText)
 import           RON.Event (ReplicaClock, getEventUuid, getEventUuids)
 import           RON.Semilattice (Semilattice)
-import           RON.Types (Object (Object), Op (Op, opId, payload, refId),
+import           RON.Types (ObjectRef (ObjectRef),
+                            Op (Op, opId, payload, refId),
                             StateChunk (StateChunk), StateFrame, UUID,
                             WireStateChunk (WireStateChunk, stateBody, stateType))
 import           RON.Util.Word (pattern B11, ls60)
@@ -337,9 +338,9 @@
             payload <- newRon item
             pure $ Op vertexId Zero payload
         modify' $ Map.insert oid $ wireStateChunk ops
-        pure $ Object oid
+        pure $ ObjectRef oid
 
-    getObject = do
+    readObject = do
         StateChunk stateBody <- getObjectStateChunk
         mItems <- for stateBody $ \Op{refId, payload} -> case refId of
             Zero -> Just <$> fromRon payload
@@ -399,13 +400,13 @@
 -- | Create an RGA from a list
 newFromList
     :: (Replicated a, MonadState StateFrame m, ReplicaClock m)
-    => [a] -> m (Object (RGA a))
+    => [a] -> m (ObjectRef (RGA a))
 newFromList = newObject . RGA
 
 -- | Create an 'RgaString' from a text
 newFromText
     :: (MonadState StateFrame m, ReplicaClock m)
-    => Text -> m (Object RgaString)
+    => Text -> m (ObjectRef RgaString)
 newFromText = newFromList . Text.unpack
 
 getAliveIndices :: (MonadE m, MonadObjectState (RGA a) m) => m [UUID]
@@ -421,7 +422,7 @@
 
 -- | Read elements from RGA
 getList :: (Replicated a, MonadE m, MonadObjectState (RGA a) m) => m [a]
-getList = coerce <$> getObject
+getList = coerce <$> readObject
 
 -- | Read characters from 'RgaString'
 getText :: (MonadE m, MonadObjectState RgaString m) => m Text
diff --git a/lib/RON/Data/VersionVector.hs b/lib/RON/Data/VersionVector.hs
--- a/lib/RON/Data/VersionVector.hs
+++ b/lib/RON/Data/VersionVector.hs
@@ -16,13 +16,13 @@
 import qualified Data.Map.Strict as Map
 
 import           RON.Data.Internal (Reducible, Rep, Replicated (encoding),
-                                    ReplicatedAsObject, getObject,
-                                    getObjectState, newObject, objectEncoding,
+                                    ReplicatedAsObject, getObjectState,
+                                    newObject, objectEncoding, readObject,
                                     reducibleOpType, stateFromChunk,
                                     stateToChunk)
 import           RON.Event (getEventUuid)
 import           RON.Semilattice (Semilattice)
-import           RON.Types (Object (Object), Op (Op, opId), UUID (UUID), WireStateChunk (WireStateChunk, stateBody, stateType))
+import           RON.Types (ObjectRef (ObjectRef), Op (Op, opId), UUID (UUID), WireStateChunk (WireStateChunk, stateBody, stateType))
 import qualified RON.UUID as UUID
 
 type Origin = Word64
@@ -79,8 +79,6 @@
         oid <- getEventUuid
         let ops = Map.elems vv
         modify' $ Map.insert oid $ wireStateChunk ops
-        pure $ Object oid
-
-    getObject = getObjectState
+        pure $ ObjectRef oid
 
-    -- rempty = mempty
+    readObject = getObjectState
diff --git a/ron-rdt.cabal b/ron-rdt.cabal
--- a/ron-rdt.cabal
+++ b/ron-rdt.cabal
@@ -1,7 +1,7 @@
 cabal-version:  2.2
 
 name:           ron-rdt
-version:        0.8
+version:        0.9
 
 bug-reports:    https://github.com/ff-notes/ron/issues
 category:       Distributed Systems, Protocol, Database
