简体   繁体   English

equal?、eql?、=== 和 == 之间有什么区别?

[英]What's the difference between equal?, eql?, ===, and ==?

I am trying to understand the difference between these four methods.我试图了解这四种方法之间的区别。 I know by default that == calls the method equal?我知道默认情况下==调用方法equal? which returns true when both operands refer to exactly the same object.当两个操作数引用完全相同的对象时返回真。

=== by default also calls == which calls equal? ===默认情况下也调用==调用equal? ... okay, so if all these three methods are not overridden, then I guess === , == and equal? ...好的,所以如果所有这三个方法都没有被覆盖,那么我猜=====equal? do exactly the same thing?做完全一样的事情?

Now comes eql?现在来了eql? . . What does this do (by default)?这有什么作用(默认情况下)? Does it make a call to the operand's hash/id?它是否调用操作数的哈希/ID?

Why does Ruby have so many equality signs?为什么Ruby有这么多等号? Are they supposed to differ in semantics?他们应该在语义上有所不同吗?

I'm going to heavily quote the Object documentation here, because I think it has some great explanations.我将在这里大量引用Object 文档,因为我认为它有一些很好的解释。 I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String .我鼓励您阅读它,以及这些方法的文档,因为它们在其他类中被覆盖,比如String

Side note: if you want to try these out for yourself on different objects, use something like this:旁注:如果您想在不同的对象上亲自尝试这些,请使用以下内容:

class Object
  def all_equals(o)
    ops = [:==, :===, :eql?, :equal?]
    Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
  end
end

"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}

== — generic "equality" == — 通用的“平等”

At the Object level, == returns true only if obj and other are the same object.在对象级别,只有当objother是同一个对象时, ==返回 true。 Typically, this method is overridden in descendant classes to provide class-specific meaning.通常,此方法在后代类中被覆盖以提供特定于类的含义。

This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.这是最常见的比较,因此也是您(作为类的作者)决定两个对象是否“相等”的最基本的地方。

=== — case equality === — 大小写相等

For class Object, effectively the same as calling #== , but typically overridden by descendants to provide meaningful semantics in case statements.对于类 Object,实际上与调用#==相同,但通常由后代覆盖以在 case 语句中提供有意义的语义。

This is incredibly useful.这非常有用。 Examples of things which have interesting === implementations:具有有趣===实现的事物示例:

  • Range范围
  • Regex正则表达式
  • Proc (in Ruby 1.9)进程(在 Ruby 1.9 中)

So you can do things like:因此,您可以执行以下操作:

case some_object
when /a regex/
  # The regex matches
when 2..4
  # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
  # the lambda returned true
end

See my answer here for a neat example of how case + Regex can make code a lot cleaner.有关case + Regex如何使代码更清晰的简洁示例,请参阅我的答案 And of course, by providing your own === implementation, you can get custom case semantics.当然,通过提供您自己的===实现,您可以获得自定义case语义。

eql? Hash equality Hash相等

The eql? eql? method returns true if obj and other refer to the same hash key.如果objother引用相同的哈希键,则方法返回 true。 This is used by Hash to test members for equality. Hash使用它来测试成员是否相等。 For objects of class Object , eql?对于Object类的Objecteql? is synonymous with == .==同义。 Subclasses normally continue this tradition by aliasing eql?子类通常通过别名eql? to their overridden == method, but there are exceptions.到他们重写的==方法,但也有例外。 Numeric types, for example, perform type conversion across == , but not across eql?例如, Numeric类型跨==执行类型转换,但不跨eql? , so: , 所以:

 1 == 1.0 #=> true 1.eql? 1.0 #=> false

So you're free to override this for your own uses, or you can override == and use alias :eql? :==所以你可以自由地覆盖它供你自己使用,或者你可以覆盖==并使用alias :eql? :== alias :eql? :== so the two methods behave the same way. alias :eql? :==所以这两种方法的行为方式相同。

equal? — identity comparison — 身份比较

Unlike == , the equal?==不同, equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b ).方法永远不应该被子类覆盖:它用于确定对象身份(即, a.equal?(b)ab是同一个对象)。

This is effectively pointer comparison.这实际上是指针比较。

I love jtbandes answer, but since it is pretty long, I will add my own compact answer:我喜欢 jtbandes 答案,但由于它很长,我将添加我自己的紧凑答案:

== , === , eql? == , === , eql? , equal? equal?
are 4 comparators, ie.是 4 个比较器,即。 4 ways to compare 2 objects, in Ruby.在 Ruby 中比较 2 个对象的 4 种方法。
As, in Ruby, all comparators (and most operators) are actually method-calls, you can change, overwrite, and define the semantics of these comparing methods yourself.由于在 Ruby 中,所有比较器(和大多数运算符)实际上都是方法调用,因此您可以自己更改、覆盖和定义这些比较方法的语义。 However, it is important to understand, when Ruby's internal language constructs use which comparator:但是,重要的是要了解 Ruby 的内部语言构造何时使用哪个比较器:

== (value comparison) == (值比较)
Ruby uses :== everywhere to compare the values of 2 objects, eg. Ruby 到处都使用 :== 来比较 2 个对象的,例如。 Hash-values:哈希值:

{a: 'z'}  ==  {a: 'Z'}    # => false
{a: 1}    ==  {a: 1.0}    # => true

=== (case comparison) === (案例比较)
Ruby uses :=== in case/when constructs. Ruby 在 case/when 构造中使用 :=== 。 The following code snippets are logically identical:以下代码片段在逻辑上是相同的:

case foo
  when bar;  p 'do something'
end

if bar === foo
  p 'do something'
end

eql? (Hash-key comparison) (哈希键比较)
Ruby uses :eql? Ruby 使用 :eql? (in combination with the method hash) to compare Hash-keys. (结合hash方法)比较Hash-keys。 In most classes :eql?在大多数课程中 :eql? is identical with :==.与 :== 相同。
Knowledge about :eql?关于 :eql 的知识? is only important, when you want to create your own special classes:仅当您想创建自己的特殊类时才重要:

class Equ
  attr_accessor :val
  alias_method  :initialize, :val=
  def hash()           self.val % 2             end
  def eql?(other)      self.hash == other.hash  end
end

h = {Equ.new(3) => 3,  Equ.new(8) => 8,  Equ.new(15) => 15}    #3 entries, but 2 are :eql?
h.size            # => 2
h[Equ.new(27)]    # => 15

Note: The commonly used Ruby-class Set also relies on Hash-key-comparison.注意:常用的 Ruby-class Set 也依赖于 Hash-key-comparison。

equal? (object identity comparison) (对象身份比较)
Ruby uses :equal? Ruby 使用 :equal? to check if two objects are identical.检查两个对象是否相同。 This method (of class BasicObject) is not supposed to be overwritten.这个方法(属于 BasicObject 类)不应该被覆盖。

obj = obj2 = 'a'
obj.equal? obj2       # => true
obj.equal? obj.dup    # => false

Equality operators: == and !=相等运算符:== 和 !=

The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not. == 运算符,也称为相等或双相等,如果两个对象相等,则返回 true,否则返回 false。

"koan" == "koan" # Output: => true

The != operator, also known as inequality, is the opposite of ==. != 运算符,也称为不等式,与 == 相反。 It will return true if both objects are not equal and false if they are equal.如果两个对象不相等,则返回 true,如果相等则返回 false。

"koan" != "discursive thought" # Output: => true

Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.请注意,具有相同元素但顺序不同的两个数组不相等,同一字母的大写和小写版本不相等等等。

When comparing numbers of different types (eg, integer and float), if their numeric value is the same, == will return true.当比较不同类型的数字(例如,整数和浮点数)时,如果它们的数值相同,== 将返回真。

2 == 2.0 # Output: => true

equal?平等的?

Unlike the == operator which tests if both operands are equal, the equal method checks if the two operands refer to the same object.与测试两个操作数是否相等的 == 运算符不同,equal 方法检查两个操作数是否引用同一个对象。 This is the strictest form of equality in Ruby.这是 Ruby 中最严格的相等形式。

Example: a = "zen" b = "zen"示例:a = "禅" b = "禅"

a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

In the example above, we have two strings with the same value.在上面的示例中,我们有两个具有相同值的字符串。 However, they are two distinct objects, with different object IDs.但是,它们是两个不同的对象,具有不同的对象 ID。 Hence, the equal?因此,平等? method will return false.方法将返回false。

Let's try again, only this time b will be a reference to a.让我们再试一次,只是这次 b 将是对 a 的引用。 Notice that the object ID is the same for both variables, as they point to the same object.请注意,两个变量的对象 ID 相同,因为它们指向同一个对象。

a = "zen"
b = a

a.object_id  # Output: => 18637360
b.object_id  # Output: => 18637360

a.equal? b  # Output: => true

eql?情商?

In the Hash class, the eql?在 Hash 类中,eql? method it is used to test keys for equality.用于测试键是否相等的方法。 Some background is required to explain this.需要一些背景来解释这一点。 In the general context of computing, a hash function takes a string (or a file) of any size and generates a string or integer of fixed size called hashcode, commonly referred to as only hash.在计算的一般上下文中,哈希函数采用任意大小的字符串(或文件)并生成称为哈希码的固定大小的字符串或整数,通常称为仅哈希。 Some commonly used hashcode types are MD5, SHA-1, and CRC.一些常用的哈希码类型是 MD5、SHA-1 和 CRC。 They are used in encryption algorithms, database indexing, file integrity checking, etc. Some programming languages, such as Ruby, provide a collection type called hash table.它们用于加密算法、数据库索引、文件完整性检查等。一些编程语言,例如 Ruby,提供了一种称为哈希表的集合类型。 Hash tables are dictionary-like collections which store data in pairs, consisting of unique keys and their corresponding values.哈希表是类似字典的集合,成对存储数据,由唯一键及其对应的值组成。 Under the hood, those keys are stored as hashcodes.在幕后,这些密钥存储为哈希码。 Hash tables are commonly referred to as just hashes.哈希表通常简称为哈希。 Notice how the word hashcan refer to a hashcode or to a hash table.请注意 hash 这个词是如何指代哈希码或哈希表的。 In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.在 Ruby 编程的上下文中,单词 hash 几乎总是指类似字典的集合。

Ruby provides a built-in method called hash for generating hashcodes. Ruby 提供了一种称为 hash 的内置方法来生成哈希码。 In the example below, it takes a string and returns a hashcode.在下面的示例中,它接受一个字符串并返回一个哈希码。 Notice how strings with the same value always have the same hashcode, even though they are distinct objects (with different object IDs).请注意具有相同值的字符串如何始终具有相同的哈希码,即使它们是不同的对象(具有不同的对象 ID)。

"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

The hash method is implemented in the Kernel module, included in the Object class, which is the default root of all Ruby objects. hash 方法在 Kernel 模块中实现,包含在 Object 类中,它是所有 Ruby 对象的默认根。 Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.一些类如 Symbol 和 Integer 使用默认实现,其他类如 String 和 Hash 提供自己的实现。

Symbol.instance_method(:hash).owner  # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel

String.instance_method(:hash).owner  # Output: => String
Hash.instance_method(:hash).owner  # Output: => Hash

In Ruby, when we store something in a hash (collection), the object provided as a key (eg, string or symbol) is converted into and stored as a hashcode.在 Ruby 中,当我们在散列(集合)中存储一些东西时,作为键(例如,字符串或符号)提供的对象被转换为并存储为散列码。 Later, when retrieving an element from the hash (collection), we provide an object as a key, which is converted into a hashcode and compared to the existing keys.稍后,当从哈希(集合)中检索元素时,我们提供一个对象作为键,将其转换为哈希码并与现有键进行比较。 If there is a match, the value of the corresponding item is returned.如果匹配,则返回相应项的值。 The comparison is made using the eql?比较是使用 eql? method under the hood.引擎盖下的方法。

"zen".eql? "zen"    # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true

In most cases, the eql?在大多数情况下,eql? method behaves similarly to the == method.方法的行为类似于 == 方法。 However, there are a few exceptions.但是,也有一些例外。 For instance, eql?例如,eql? does not perform implicit type conversion when comparing an integer to a float.将整数与浮点数进行比较时,不执行隐式类型转换。

2 == 2.0    # Output: => true
2.eql? 2.0    # Output: => false
2.hash == 2.0.hash  # Output: => false

Case equality operator: ===大小写相等运算符:===

Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as case-equality, triple equals or threequals.许多 Ruby 的内置类,例如 String、Range 和 Regexp,都提供了自己的 === 运算符实现,也称为 case-equality、triple equals 或threequals。 Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on.因为它在每个类中的实现不同,所以它的行为会根据它被调用的对象类型而不同。 Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left.通常,如果右侧的对象“属于”或“是”左侧对象的成员,则返回 true。 For instance, it can be used to test if an object is an instance of a class (or one of its subclasses).例如,它可用于测试对象是否是类(或其子类之一)的实例。

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

The same result can be achieved with other methods which are probably best suited for the job.使用可能最适合该工作的其他方法也可以获得相同的结果。 It's usually better to write code that is easy to read by being as explicit as possible, without sacrificing efficiency and conciseness.在不牺牲效率和简洁性的情况下,编写尽可能明确的易于阅读的代码通常会更好。

2.is_a? Integer   # Output: => true
2.kind_of? Integer  # Output: => true
2.instance_of? Integer # Output: => false

Notice the last example returned false because integers such as 2 are instances of the Fixnum class, which is a subclass of the Integer class.请注意,最后一个示例返回 false,因为诸如 2 之类的整数是 Fixnum 类的实例,它是 Integer 类的子类。 The ===, is_a? ===, is_a? and instance_of?和instance_of? methods return true if the object is an instance of the given class or any subclasses.如果对象是给定类或任何子类的实例,则方法返回 true。 The instance_of method is stricter and only returns true if the object is an instance of that exact class, not a subclass. instance_of 方法更严格,仅当对象是该类的实例而不是子类时才返回 true。

The is_a? is_a? and kind_of?和种类? methods are implemented in the Kernel module, which is mixed in by the Object class.方法在 Kernel 模块中实现,由 Object 类混入。 Both are aliases to the same method.两者都是同一方法的别名。 Let's verify:我们来验证一下:

Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # Output: => true Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # 输出:=> true

Range Implementation of === ===的范围实现

When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.在范围对象上调用 === 运算符时,如果右侧的值落在左侧的范围内,则返回 true。

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

Remember that the === operator invokes the === method of the left-hand object.请记住 === 运算符调用左侧对象的 === 方法。 So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.所以 (1..4) === 3 等价于 (1..4).=== 3. 换句话说,左边操作数的类将定义 === 方法的哪个实现调用,因此操作数位置不可互换。

Regexp Implementation of === ===的正则表达式实现

Returns true if the string on the right matches the regular expression on the left.如果右侧的字符串与左侧的正则表达式匹配,则返回 true。 /zen/ === "practice zazen today" # Output: => true # is the same as "practice zazen today"=~ /zen/ /zen/ === "practice zazen today" # 输出:=> true # 和 "practice zazen today"=~ /zen/

Implicit usage of the === operator on case/when statements在 case/when 语句中隐式使用 === 运算符

This operator is also used under the hood on case/when statements.此运算符也用于 case/when 语句的幕后。 That is its most common use.这是它最常见的用途。

minutes = 15

case minutes
  when 10..20
    puts "match"
  else
    puts "no match"
end

# Output: match

In the example above, if Ruby had implicitly used the double equal operator (==), the range 10..20 would not be considered equal to an integer such as 15. They match because the triple equal operator (===) is implicitly used in all case/when statements.在上面的例子中,如果 Ruby 隐式地使用了双等号运算符 (==),那么范围 10..20 将不会被视为等于 15 之类的整数。它们匹配是因为三重等号运算符 (===) 是在所有 case/when 语句中隐式使用。 The code in the example above is equivalent to:上面例子中的代码等价于:

if (10..20) === minutes
  puts "match"
else
  puts "no match"
end

Pattern matching operators: =~ and !~模式匹配运算符:=~ 和 !~

The =~ (equal-tilde) and !~ (bang-tilde) operators are used to match strings and symbols against regex patterns. =~ (equal-tilde) 和 !~ (bang-tilde) 运算符用于根据正则表达式模式匹配字符串和符号。

The implementation of the =~ method in the String and Symbol classes expects a regular expression (an instance of the Regexp class) as an argument. String 和 Symbol 类中 =~ 方法的实现需要一个正则表达式(Regexp 类的一个实例)作为参数。

"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

:zazen =~ /zen/    # Output: => 2
:zazen =~ /discursive thought/  # Output: => nil

The implementation in the Regexp class expects a string or a symbol as an argument. Regexp 类中的实现需要一个字符串或一个符号作为参数。

/zen/ =~ "practice zazen"  # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil

In all implementations, when the string or symbol matches the Regexp pattern, it returns an integer which is the position (index) of the match.在所有实现中,当字符串或符号匹配 Regexp 模式时,它返回一个整数,它是匹配的位置(索引)。 If there is no match, it returns nil.如果没有匹配项,则返回 nil。 Remember that, in Ruby, any integer value is "truthy" and nil is "falsy", so the =~ operator can be used in if statements and ternary operators.请记住,在 Ruby 中,任何整数值都是“真”而 nil 是“假”,因此 =~ 运算符可用于 if 语句和三元运算符。

puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes

Pattern-matching operators are also useful for writing shorter if statements.模式匹配运算符对于编写较短的 if 语句也很有用。 Example:例子:

if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
  true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end

The !~ operator is the opposite of =~, it returns true when there is no match and false if there is a match. !~ 运算符与 =~ 相反,不匹配时返回真,匹配时返回假。

More info is available at this blog post . 这篇博文提供了更多信息。

Ruby exposes several different methods for handling equality: Ruby 公开了几种不同的处理相等性的方法:

a.equal?(b) # object identity - a and b refer to the same object

a.eql?(b) # object equivalence - a and b have the same value

a == b # object equivalence - a and b have the same value with type conversion.

Continue reading by clicking the link below, it gave me a clear summarized understanding.单击下面的链接继续阅读,它给了我一个清晰的总结性理解。

https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers

Hope it helps others.希望它可以帮助其他人。

I would like to expand on the === operator.我想扩展===运算符。

=== is not an equality operator! ===不是等号运算符!

Not.不是。

Let's get that point really across.让我们真正了解这一点。

You might be familiar with === as an equality operator in Javascript and PHP, but this just not an equality operator in Ruby and has fundamentally different semantics.您可能熟悉===在 Javascript 和 PHP 中作为相等运算符,但这在 Ruby 中不是相等运算符,并且具有根本不同的语义。

So what does === do?那么===什么作用呢?

=== is the pattern matching operator! ===是模式匹配运算符!

  • === matches regular expressions ===匹配正则表达式
  • === checks range membership ===检查范围成员资格
  • === checks being instance of a class ===检查是一个类的实例
  • === calls lambda expressions ===调用 lambda 表达式
  • === sometimes checks equality, but mostly it does not ===有时会检查相等性,但大多数情况下不会

So how does this madness make sense?那么这种疯狂有什么意义呢?

  • Enumerable#grep uses === internally Enumerable#grep内部使用===
  • case when statements use === internally语句在内部使用=== case when
  • Fun fact, rescue uses === internally有趣的事实, rescue内部使用===

That is why you can use regular expressions and classes and ranges and even lambda expressions in a case when statement.这就是为什么您可以在case when语句中使用正则表达式、类和范围甚至 lambda 表达式的原因。

Some examples一些例子

case value
when /regexp/
  # value matches this regexp
when 4..10
  # value is in range
when MyClass
  # value is an instance of class
when ->(value) { ... }
  # lambda expression returns true
when a, b, c, d
  # value matches one of a through d with `===`
when *array
  # value matches an element in array with `===`
when x
  # values is equal to x unless x is one of the above
end

All these example work with pattern === value too, as well as with grep method.所有这些示例也适用于pattern === value ,以及grep方法。

arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)                                                                                                                            
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]

=== #---case equality === #---大小写相等

== #--- generic equality == #--- 泛型相等

both works similar but "===" even do case statements两者的工作原理相似,但“===”甚至执行 case 语句

"test" == "test"  #=> true
"test" === "test" #=> true

here the difference这里的区别

String === "test"   #=> true
String == "test"  #=> false
  1. .eql? .eql? - This operator returns true if the receiver and argument have both the same type and equal values. - 如果接收者和参数具有相同的类型和相等的值,则此运算符返回 true。

for example - 10.eql?(10.0) is false.例如 - 10.eql?(10.0) 是假的。

  1. === - it will test equality in case statement. === - 它将测试 case 语句中的相等性。

for example - (1...10) === 1 is true例如 - (1...10) === 1 是真的

  1. == - This operator checks whether the two given operands are equal or not. == - 此运算符检查两个给定的操作数是否相等。 If equals, it returns TRUE, Otherwise it returns FALSE.如果相等,则返回 TRUE,否则返回 FALSE。

for example - (1...10) == 1 is false例如 - (1...10) == 1 是假的

for more example click here有关更多示例,请单击此处

I wrote a simple test for all the above.我为上述所有内容编写了一个简单的测试。

def eq(a, b)
  puts "#{[a, '==',  b]} : #{a == b}"
  puts "#{[a, '===', b]} : #{a === b}"
  puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
  puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end

eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM