Michael, you gave a very good and complete explanation.
Perhaps what Daniil is looking for is TensorDimensions?
In[1]:= Dimensions[Sqrt[2]]
TensorDimensions[Sqrt[2]]
Out[1]= {2}
Out[2]= {}
I have to say that I have not found this to be an issue when the object appears in lists (like when I need to get the dimensions of an array). Typically what one needs is the dimensions of the list containing the object and Mathematica does not need to "go inside" the object itself. The example below may clarify what I mean:
In[3]:= Dimensions[{{Sqrt[2], E}, {\[Pi], 3}}]
TensorDimensions[{{Sqrt[2], E}, {\[Pi], 3}}]
Out[3]= {2, 2}
Out[4]= {2, 2}
Even in a situation like the next one below, Dimensions still gives the same answer as TensorDimensions, despite the fact that each one of the objects has length 2. In this case it is the change of heads from one level to the next what does the trick, as Michael explained (here at each level all the objects have the same head, and all have Length 2, but Dimensions does not print {2, 2, 2}).
In[5]:= Dimensions[{{Sqrt[2], Sqrt[3]}, {Sqrt[5], Sqrt[7]}}]
TensorDimensions[{{Sqrt[2], Sqrt[3]}, {Sqrt[5], Sqrt[7]}}]
Out[5]= {2, 2}
Out[6]= {2, 2}
There may be more situations where Dimensions and TensorDimensions give different results.
You may also want to look at the outputs of the Depth function on examples like the ones above and at the results of Mapping the Length function on those arrays at different levels.
Hope this helps,
Otto Linsuain