What is the difference between `size` and `length` methods
Asked Answered
H

6

31

When I ran size and length on a string, they returned the same value.

"akash".size # => 5
"akash".length # => 5

What is the difference between these two methods?

Hame answered 5/3, 2016 at 16:38 Comment(4)
A more interesting question would be: Why is one not an alias of the other, but both are defined independently with the same code?Airframe
yes please enlighten me with ansHame
In MRI at least they’re identical: github.com/ruby/ruby/blob/v2_3_0/string.c#L9392-L9393, both implemented with the C function rb_str_length.Amsterdam
@Amsterdam That's an implementation detail at the VM or interpreter level. The parser thinks they're two different methods.Herzig
H
34

Summary

In Ruby, methods can be overridden, so there are classes where there are multiple methods that lead to the same results so that behavior can be easily overridden in one method without affecting the other. Some classes do this using separate methods, while other classes implement this behavior as aliases.

Which is which, and why, is often a language implementation decision that can't be answered canonically without asking the Ruby Core team members who implemented the code. As such, that portion of the question is out of scope for Stack Overflow. Assuming that aliased methods are not expected to be monkey-patched as often as work-alike methods is a reasonable assumption, but it is only that: an assumption.

If you need a truly canonical answer, you will have to dig through the SVN source, search the bug tracker discussions, or ask the Core Team directly. However, I provide a pragmatic analysis below.

String Class: Different Methods

For example, the Ruby String#size and String#length methods are actually separate methods, but internally Ruby calls the same C source code to implement them both:

rb_str_length(VALUE str)
{
    return LONG2NUM(str_strlen(str, NULL));
}

This is purely an implementation detail. From the Ruby VM's point of view, they are really separate methods that just happen to share an underlying C implementation for speed. You should be able to redefine #size or #length on a String object without changing the behavior of both, although doing so often interferes with a REPL such as Pry or IRB.

Array Class: Aliased Methods

On the other hand, some classes implement #size and #length as aliases. For example, Array#size is explicitly defined as an alias for Array#length. As a result, this creates a copy of the original method name as #size, so you should be able to redefine the aliased version without changing the behavior of the original #length method.

Parting Thoughts

This issue is really a difference of implementation, not behavior. In practice, it would appear the only meaningful distinction lies in which Ruby component implements the work-alike behavior. There may be legacy reasons, performance reasons, or it may simply be a bug that no one has cared enough about to file or fix.

Since the behavior is sane, and doesn't really violate the Principle of Least Surprise, I'd treat it as a minor language quirk. However, anyone who feels more strongly about it should definitely file a bug.

Herzig answered 5/3, 2016 at 18:14 Comment(3)
I think I should report that as a bug on Ruby core.Airframe
Are you sure about "If you change the behavior of #length, you will change the behavior of #size"? Isn't aliasing done within Ruby core, before you have chance to overwrite them?Airframe
It is not a bug because the aliases are independent; they are not aliases. They are bug in the sense that the aliashood is inconsistent.Airframe
W
7

There's no difference between size and length of strings. Which one you prefer is essentially a matter of style.

Watershed answered 5/3, 2016 at 16:42 Comment(1)
is the same for length and count as well (w.r.t. arrays)?Dhiman
C
4

Contrary to what others have said, there is at least one differences between .length and .size in terms of usage.

.size may be used on integers, whereas .length raises a NoMethodError.

Contention answered 15/7, 2021 at 13:21 Comment(0)
D
3

They are identical. It's just alias.

Check this article for more info, also on count.

Declared answered 5/3, 2016 at 16:43 Comment(1)
Actually, they aren't aliases. "".method(:size).original_name # => :size. "".method(:length).original_name # => :length.Airframe
B
0

I prefer size since it saves me typing/reading 2 characters.

Brunel answered 11/12, 2023 at 15:21 Comment(0)
V
0

In RUBY there is no difference between size and length.

"length" and "size" are aliases for each other. FYI

enter image description here

But in Ruby On Rails(ROR), there is a big difference between them.

length

Returns the size of the collection calling size on the target. If the collection has been already loaded, length and size are equivalent. If not and you are going to need the records anyway this method will take one less query. Otherwise size is more efficient.

size

Returns the size of the collection. If the collection hasn't been loaded, it executes a SELECT COUNT(*) query. Else it calls collection.size.

If the collection has been already loaded size and length are equivalent. If not and you are going to need the records anyway length will take one less query. Otherwise size is more efficient.

when you are implementing relation group, there is a very big difference between them.

Differences query.length:

Retrieves all the grouped records and then counts them. This can be slower and uses more memory as it involves retrieving and storing the full dataset before counting.

query.size:

Returns a count of the grouped results, not the actual records. This is faster and uses less memory since it doesn't need to load the actual records into memory.

(byebug) Role.group(:name, :id).length
  Role Load (54.3ms)  SELECT "roles".* FROM "roles" WHERE "roles"."type" = $1 GROUP BY "roles"."name", "roles"."id"  [["type", "Role"]]
6
(byebug) Role.group(:name, :id).size
   (50.4ms)  SELECT COUNT(*) AS count_all, "roles"."name" AS roles_name, "roles"."id" AS roles_id FROM "roles" WHERE "roles"."type" = $1 GROUP BY "roles"."name", "roles"."id"  [["type", "Role"]]
{["yue", 6]=>1, ["staff", 1]=>1, ["partner", 3]=>1, ["forbidden", 5]=>1, ["admin", 2]=>1, ["external_staff", 4]=>1}
(byebug)
  • Role.group(:name, :id).length execute the SQL
Role Load (54.3ms)  SELECT "roles".* FROM "roles" WHERE "roles"."type" = $1 GROUP BY "roles"."name", "roles"."id"  [["type", "Role"]]

and gets result

6
  • Role.group(:name, :id).size does this:
SELECT COUNT(*) AS count_all, "roles"."name" AS roles_name, "roles"."id" AS roles_id FROM "roles" WHERE "roles"."type" = $1 GROUP BY "roles"."name", "roles"."id"  [["type", "Role"]]

gets result

{["yue", 6]=>1, ["staff", 1]=>1, ["partner", 3]=>1, ["forbidden", 5]=>1, ["admin", 2]=>1, ["external_staff", 4]=>1}
Venepuncture answered 12/6 at 8:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.