diff --git a/src/polymesh/attributes.hh b/src/polymesh/attributes.hh
index d30c5b815477cd39b72f3440aaa121311bfee87a..8e3688fc60e25c6144cb82abda07259c01137266 100644
--- a/src/polymesh/attributes.hh
+++ b/src/polymesh/attributes.hh
@@ -108,11 +108,13 @@ public:
     void compute(FuncT&& f);
 
     template <class FuncT>
-    auto view(FuncT&& f) const -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>;
-#ifndef _MSC_VER // cannot overload this apparently
+    auto view(FuncT&& f) & -> attribute_view<primitive_attribute<tag, AttrT>&, FuncT>;
+    template <class FuncT>
+    auto view(FuncT&& f) const& -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>;
     template <class FuncT>
     void view(FuncT&& f) && = delete;
-#endif
+    template <class FuncT>
+    void view(FuncT&& f) const&& = delete;
 
     // template <class ReadT, class WriteT>
     // auto view(ReadT&& r, WriteT&& w) -> readwrite_property<primitive_attribute<tag, AttrT>, ReadT, WriteT>;
diff --git a/src/polymesh/impl/impl_attributes.hh b/src/polymesh/impl/impl_attributes.hh
index b8aa5a8eb200ee0e8b0f151d19d60b37ed1ec826..470586cfff742b93740217b1e7c0bc31e913daa3 100644
--- a/src/polymesh/impl/impl_attributes.hh
+++ b/src/polymesh/impl/impl_attributes.hh
@@ -439,9 +439,16 @@ void primitive_attribute<tag, AttrT>::compute(FuncT&& f)
 
 template <class tag, class AttrT>
 template <class FuncT>
-auto primitive_attribute<tag, AttrT>::view(FuncT&& f) const -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>
+auto primitive_attribute<tag, AttrT>::view(FuncT&& f) const& -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>
 {
     return attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>(*this, std::forward<FuncT>(f));
 }
 
+template <class tag, class AttrT>
+template <class FuncT>
+auto primitive_attribute<tag, AttrT>::view(FuncT&& f) & -> attribute_view<primitive_attribute<tag, AttrT>&, FuncT>
+{
+    return attribute_view<primitive_attribute<tag, AttrT>&, FuncT>(*this, std::forward<FuncT>(f));
+}
+
 } // namespace polymesh
diff --git a/src/polymesh/view.hh b/src/polymesh/view.hh
index 86e64ef801b6e813a8ba89c42c491bd963547490..f0a7065b9bd7f9a06d2ad1ea1469fa633ff31c61 100644
--- a/src/polymesh/view.hh
+++ b/src/polymesh/view.hh
@@ -8,30 +8,36 @@ namespace polymesh
 template <class CollectionT, class FuncT>
 struct attribute_view
 {
-    attribute_view(CollectionT collection, FuncT func) : mCollection(collection), mFunc(std::move(func)) {}
+    attribute_view(CollectionT& collection, FuncT func) : mCollection(collection), mFunc(std::move(func)) {}
 
     using index_t = typename std::decay<CollectionT>::type::index_t;
     using handle_t = typename std::decay<CollectionT>::type::handle_t;
     using input_t = decltype(std::declval<CollectionT>()[index_t()]);
     using output_t = typename tmp::decayed_result_type_of<FuncT, input_t>;
 
-    output_t operator[](handle_t h) const { return mFunc(mCollection(h)); }
-    output_t operator[](index_t h) const { return mFunc(mCollection(h)); }
+    decltype(auto) operator[](handle_t h) const { return mFunc(mCollection(h)); }
+    decltype(auto) operator[](index_t h) const { return mFunc(mCollection(h)); }
 
-    output_t operator()(handle_t h) const { return mFunc(mCollection(h)); }
-    output_t operator()(index_t h) const { return mFunc(mCollection(h)); }
+    decltype(auto) operator()(handle_t h) const { return mFunc(mCollection(h)); }
+    decltype(auto) operator()(index_t h) const { return mFunc(mCollection(h)); }
+
+    decltype(auto) operator[](handle_t h) { return mFunc(mCollection(h)); }
+    decltype(auto) operator[](index_t h) { return mFunc(mCollection(h)); }
+
+    decltype(auto) operator()(handle_t h) { return mFunc(mCollection(h)); }
+    decltype(auto) operator()(index_t h) { return mFunc(mCollection(h)); }
 
     int size() const { return mCollection.size(); }
 
     template <class F>
     auto map(F&& f) const
     {
-        auto f2 = [ff = std::forward<F>(f)](output_t const& v) { return ff(v); };
-        return attribute_view<CollectionT, decltype(f2)>(mCollection, std::move(f2));
+        auto new_f = [f0 = mFunc, f1 = std::forward<F>(f)](auto&& v) -> decltype(auto) { return f1(f0(v)); };
+        return attribute_view<CollectionT, decltype(new_f)>(mCollection, std::move(new_f));
     }
 
 private:
-    CollectionT mCollection;
+    CollectionT& mCollection;
     FuncT mFunc;
 };
 }