I'm going to use Nim in new project for the Server of Web Applications. I read tutorials, but one thing is not clear to me - how should I decide when to use object and when to use ref?
In Servers like Ruby on Rails or Java - the refs are used everywhere except of the basic types like Integers etc. I wonder should I just always use refs in Nim too?
In Java - I never had to think about it or choose between ref or object and I try to figure out some simple rule that I could use in Nim - like just use refs everywhere, or maybe not use it at all.
A word about performance - I'm not trying to achieve top performance. I would prefer to have simplicity and average performance instead of more complicated code and high performance.
If we consider a common web application - a blog. The kind of work that needs to be done will be 1) define some objects 2) manipulate with sequences of that objects 3) render it, the pseudocode:
import sequtils, sugar
type
Post = object
title: string
text: string
author: string
let db = @[
Post(title: "post 1", text: "text 1", author: "alex"),
Post(title: "post 2", text: "text 2", author: "jim"),
]
# Doing some manipulations, lots of iterations with
# sequences like filtering, mapping etc.
let posts = db.filter(post => post.author == "alex")
# Rendering
echo posts.map(post => post.title)
In this example I defined Post as object, without ref.
And it seems like that would be wrong, right? Because those objects (like post) will be copied a lot in operations with sequences. So it seems like it would be better to use ref object in such cases?
>I'm going to try "always use ref" way then
That is not very smart. And I wonder why you have asked then at all?
Indeed I think the answer is not that easy -- I would try to use value objects whenever possible, and fall back to refs when necessary, or when the benefit of refs is obvious. Refs mean indirection, expensive heap allocation and deallocation. Value objects can mean copy, sometimes, but copy is not so slow as some people think.
ref is similar to a pointer except that the garbage collector handles it. if you think about how a ref is created
type
simpleRef = ref simpleObj
simpleObj = object
proc createSimpleRef():simpleRef =
result = new simpleObj
the new keyword just allows the GC to allocate space for the simpleObj and lets it keep track of if it is still being used or can be freed
generally if you are planning on creating an object once and using it in many places, i would recommend a ref but if you plan on using an object quickly say just inside a proc then a simple object would do fine
And I wonder why you have asked then at all?
I had an idea to always use refs or always use objects. But was not sure which one would be better and if maybe it's too crazy. So I asked.
to always use refs or always use objects.
You intent to always use only one of them?
Yes, then you have to use refs of course, as value objects do not always work. For inheritance you need ref objects, for many to one data structures you need refs, for dynamic structures like trees you may need refs. That is why languages like Java. Ruby, Python use hidden refs always.
Refs mean indirection, expensive heap allocation and deallocation, and does not benefit much from cache
But is it slow actually? Isn't Java works that way - everything except of primitive types like int is ref?
And Java is fast. Yes Java may be slower compared to C in benchmark numbers. But for any practical case - Java performance will be more than enough for most cases.
So how could you call that slow?
So how could you call that slow?
So why do you intend to use Nim at all -- when you do not like the fact that Nim have value and ref objects?
Araq told you once that Go makes this distinction too. Both types have advantages and disadvantages. For one case a copy of a value type may make it slow, for other cases the heap allocation and unfriendly cache usage may make it slow.
I think Java has some magic -- I know that Java can be fast in some benchmarks -- but do we really know what happens internally?
So don't care too much, use ref when you want to never think about it again.
Personally, I use object as much as possible.
What is lost by some copies, I expect it to be recovered by an optimizer which will not be disturbed by assignments via references. For global optimization, better use a strong typed language and avoid aliasing.
I think that, on this respect, over time Nim should become an awesome language.
The golden rule is if your instance is unique and non-interchangeable with another, use ref object, this is true for a Person (even if another has the same amount of arms and legs and heads it's not the same person), database connections, file handles, sockets or memory handle (like GPU memory)
If your object is fungible (one dollar is the same as another dollar, one bullet or particle or triangle is the same as another with the same characteristics) use an object.
Plain object have a lot of advantages:
Ergo, if you ever want to do multithreading in the future, use ref as little as necessary, that would be that much less refactoring to day later.
But is it slow actually?
Yes.
Isn't Java works that way - everything except of primitive types like int is ref?
True.
And Java is fast.
No.
Yes Java may be slower compared to C in benchmark numbers. But for any practical case - Java performance will be more than enough for most cases.
This is simply an assertion that it doesn't matter that it's slow, or that it's not slow enough to matter.
So how could you call that slow?
By being factual, rather than indulging in circular reasoning and sophistry.