Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Tweaked legacy documentation is misleading and does not fit in the context #34414

Open
WenjieZ opened this issue Jan 17, 2020 · 18 comments
Labels
docs This change adds or pertains to documentation

Comments

@WenjieZ
Copy link

WenjieZ commented Jan 17, 2020

In the types doc page, it says

Immutable composite types with no fields are singletons; there can be only one instance of such types:

julia> struct NoFields
       end

julia> NoFields() === NoFields()
true

Nonetheless, === is not a valid way to test singletons. In the doc page of ===, it says

First the types of x and y are compared. If those are identical, mutable objects are compared by address in memory and immutable objects (such as numbers) are compared by contents at the bit level.

Therefore, === is the same as == for immutable types, and it does not compare the addresses. Indeed, I tried another immutable type but with fields; the result is the same.

Then, I tested it for mutable types, and there was no chance:

julia> mutable struct NoFields
       end

julia> NoFields() == NoFields()
false

julia> NoFields() === NoFields()
false

In conclusion, the doc is wrong and misleading.

@KristofferC
Copy link
Member

In conclusion, the doc is wrong and misleading.

Could you spell out more directly what is wrong and misleading?

@WenjieZ
Copy link
Author

WenjieZ commented Jan 17, 2020

Could you spell out more directly what is wrong and misleading?

Doc's thesis: struct NoFields end's object is a singleton.

Doc uses an example to prove it.

Doc's thesis: Immutable composite types with no fields are singletons

Doc uses struct NoFields end to prove it.

I criticize that the Doc's example is not a valid proof.

@KristofferC
Copy link
Member

You mean it is not a valid "proof" because even if the struct would have fields it would still compare ===?

Then, I tested it for mutable types, and there was no chance:

But how is this relevant when it is explicitly mentioned that a singleton has to be non-mutable?

@WenjieZ
Copy link
Author

WenjieZ commented Jan 17, 2020

Maybe my expressions are too complex. I'll post in the following the misleading paragraphs:


Immutable composite types with no fields are singletons; there can be only one instance of such types:

julia> struct NoFields
       end

julia> NoFields() === NoFields()
true

The === function confirms that the "two" constructed instances of NoFields are actually one and the same.


You see? The last sentence is wrong.

@WenjieZ
Copy link
Author

WenjieZ commented Jan 17, 2020

Counter-example:

julia> struct YesFields
         x
       end

julia> YesFields(1) == YesFields(1)
true

julia> YesFields(1) === YesFields(1)
true

@KristofferC
Copy link
Member

So previously, MutableNoFields() === MutableNoFields()but this was changed in #25854. When that got changed, the existing docs was tweaked to say that the struct had to be immutable(#25862) . However, as you say, there is no longer anything specific about it having no fields. I think the docs about singletons can just be removed since they are not special anymore.

@WenjieZ
Copy link
Author

WenjieZ commented Jan 17, 2020

Thank you for confirming that. I'll file a PR.

@yuyichao
Copy link
Contributor

Counter-example:

No that is not a counter example. Your example proofs that there is ever only one instance of YesFields(1).

@yuyichao
Copy link
Contributor

In another word, === is absolutely correct way to determine if the two objects are infact the same one and the fact that the two NoFields() compares the same proof that they are the same object. There is nothing logically wrong about it.

While it is also true that this property can now be seen as an extention of the semantics of immutable types, it does not invalidate the proof here. And despite this part of the semantics not being very special, singleton type still worth mentioning. In fact, this is where singleton type is defined on this page. If anything, you can add clarification that the semantics is consistent with normal composite types.

The section about "Singleton Types" below does indeed seem confusing since it is used there to only mean Type{T} but singleton types is used to mean other immutable composite types with no fields elsewhere (NoField and Nothing).

@WenjieZ WenjieZ changed the title [Doc] === is not a valid way to test singletons [Doc] Tweaked legacy documentation is misleading and does not fit in the context Jan 17, 2020
@Keno
Copy link
Member

Keno commented Jan 18, 2020

Agreed on the confusing docs here, but it is worth mentioning in the devdocs that singleton types only ever have one boxed representation, which is fairly critical (so e.g. boxing nothing doesn't allocate).

@WenjieZ
Copy link
Author

WenjieZ commented Jan 21, 2020

It seems to me that the concept of singleton in Julia is not properly defined. In other languages, such as C++, a singleton's constructor is a private method. However, in Julia, you can freely and repeatedly construct it by calling the constructor:

julia> Nothing() === nothing
true

In addition, if the address is the golden rule of testing singletons, then the method of === becomes questionable:

julia> a = "123"
"123"

julia> b = "123"
"123"

julia> pointer(a)
Ptr{UInt8} @0x00007fe97ae879f8

julia> pointer(b)
Ptr{UInt8} @0x00007fe97ae79318

julia> a === b
true

@StefanKarpinski
Copy link
Member

StefanKarpinski commented Jan 21, 2020

It's very much well defined:

  • A singleton type is a type which exactly one value.
  • The notion of whether two things are the same value is given by the === relation.

So a singleton type is a type for which at least one instance exists and for which all instances are === to that one instance.

@StefanKarpinski
Copy link
Member

Regarding pointer on strings: the pointer function is not pure—it will give a pointer to memory that has the value you passed to it in it, but it's not guaranteed to always be the same pointer. So that argument is similar to saying that this is questionable:

julia> a = 1
1

julia> b = 1
1

julia> rand(a)
1-element Array{Float64,1}:
 0.1397043590719047

julia> rand(b)
1-element Array{Float64,1}:
 0.7414452172136339

julia> a === b
true

@WenjieZ
Copy link
Author

WenjieZ commented Jan 22, 2020

@StefanKarpinski Maybe we shouldn't call it "singleton"; we could call it "equivalent class" formed by the relationship ===.

@StefanKarpinski
Copy link
Member

StefanKarpinski commented Jan 22, 2020

It’s the textbook definition of a singleton type: a type with exactly one instance.

06777DBB-1562-44BE-960E-37F28465AD03
B9F864B2-27C0-43BB-A299-E76F4FAC36B5

@WenjieZ
Copy link
Author

WenjieZ commented Jan 31, 2020

Sorry for my delayed reply: I was fighting against the epidemic in China.

Finally, I realized the divergence between @StefanKarpinski and me.
You were talking about singleton types, popularized by the Scala language, whereas I was talking about singleton design patterns, popularized by the Gang of Four.

  • The former is a type that permits one and only one value; the latter is a class that permits at most one instance.
  • The former is a compile-time concept, which facilitates for the compiler the function signature alignment; the latter is a run-time concept, which forbids duplicated resource allocations.

If you agree, I would say the singleton type in Scala is equivalent to the value-type in Julia.
However, when the manual contributor was writing the paragraphs cited below and when @Keno as well as the other readers were reading it, they were thinking about the singleton design pattern rather than the singleton type.
That's why I proposed the removal of the following paragraph from the manual.


Immutable composite types with no fields are singletons; there can be only one instance of such types:

julia> struct NoFields
       end

julia> NoFields() === NoFields()
true

The === function confirms that the "two" constructed instances of NoFields are actually one and the same.

@StefanKarpinski
Copy link
Member

Sorry for my delayed reply: I was fighting against the epidemic in China.

Take care, I hope you are well and safe!

If you can propose some clarification that would have helped you understand that the difference, that would be great. The word "pattern" doesn't appear anywhere when talking about singletons and if you parse the sentence you wanted to remove, the adjective "singleton" modifies the noun "type". Note that the word singleton predates the Gang of Four book and is more general than the design pattern—OOP does not own the word.

@StefanKarpinski
Copy link
Member

I should, perhaps also point out, that the singleton design pattern is just a way of implementing a singleton type in a language that doesn't naturally have them. In OOP languages, since objects have object identity (because they are mutable and have private state, they have to), so the only way to implement a singleton type in such a language is to prevent instantiation of more than one instance at runtime. In languages like Julia, where real singleton types exist, that isn't necessary.

@ViralBShah ViralBShah added the docs This change adds or pertains to documentation label Mar 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation
Projects
None yet
Development

No branches or pull requests

6 participants