Иван Кузьмицкий писал(а):
Vlad писал(а):
Это ж какие там запрятанные нюансы? Что у базового типа можно вызвать ToString()? В чем загадка-то?
Загадка - зачем целочисленному типу иметь метод преобразования в строку? Ну объясните, почему целое число (число - сущность некоторой природы) надо рассматривать как объект (структура совершенно другой природы)? Почему число (число - которое от 0 до MAX(INT)) должно иметь метод (ну это бред сивой кобылы) преобразования этого числа в строку?
Вы никогда не печатали числа в консоль или в GUI-виджет?
Ну тогда я даже не представляю себе, какими задачами Вы занимаетесь, что можете обходиться без чисел... :о)
Для меня загадка с методом ToSring() в .NET'е в другом.
Я вот привык, что в том же Хаскелле функция show (метод класса типов Show) выдаёт строку с каким-нибудь вменяемым представлением того значения, к которому она представляется. Скажем, так:
Код:
Hugs> show 1 -- целое число
"1"
Hugs> show 3.14 -- вещественное число
"3.14"
Hugs> show True -- булево значение
"True"
Hugs> show [1, 2, 3] -- список целых чисел
"[1,2,3]"
Hugs> show (1, False, "abc") -- кортёж из целого числа, булева значения и строки
"(1,False,\"abc\")"
Конечно, для новых пользовательских типов этот метод может быть определён как угодно, это зависит от конкретного аффтара, но всё-таки принято эту функцию заставлять выдавать внутреннее представление значения во логически обоснованном виде.
А что мы видим в .NET'е? (смотрим в интерпретаторе F#)
Код:
> 1.ToString();;
1.ToString();; // ну хорошо, понятно, тут я лажанулся...
^^^^^^^^^^^
stdin(1,0): error FS0191: This is not a valid numeric literal. Sample formats include 4, 0x4, 0b0100, 4L, 4UL, 4u, 4s, 4us, 4y, 4uy, 4.0, 4.0f, 4N, 4I.
> val it : unit = ()
> (1).ToString();; -- целое число
val it : string = "1"
> (3.14).ToString();; -- вещественное число
val it : string = "3,14"
> true.ToString();; -- булево значение
val it : string = "True"
> [1; 2; 3].ToString();; -- список целых чисел
val it : string = "Microsoft.FSharp.Collections.List`1+_Cons[System.Int32]"
// опаньки! это что ещё за фигня? Мне не нужно имя типа этого списка, мне нужно его самого! 8-o
> (1, false, "abc").ToString();;
val it : string = "Microsoft.FSharp.Core.Tuple`3[System.Int32,System.Boolean,System.String]"
В C# такая же история
Код:
int[] arr = new int[] { 1, 2, 3};
textBox.Text = arr.ToString();
В textBox.Text помещается строка "System.Int32[]"
Допустим, определяем мы в Хаскелле такой тип-запись:
Код:
data Rec = Rec { str :: String, num :: Integer, flag :: Bool}
deriving (Show)
Затем в интерпретаторе с удовольствием наблюдаем, что автоматически сгенерированный для нашего типа метод show (эту генерацию мы указали описанием
deriving (Show)) выдаёт более-менее разумную строку:
Код:
Main> show Rec { str = "abc", num = 1, flag = True }
"Rec {str = \"abc\", num = 1, flag = True}"
В F# классов типов, к сожалению, нет, система типов там -- жуткий гибрид традиционного для ML-семейства системы Хиндли-Милнера + OCaml'евский ООП + .NET'овский ООП.
Вообще, F# переусложнённый язык -- он включает в себя OCaml как своё подмножество, плюс к этому автор F# решид сжелать его полноценным языком для .NET'a, а это значит, что должна быть поддержка всего, что есть в С# -- дженерики, анонимные делегаты (это вообще песня! но необходимо для полноценного интеропа с C#), LINQ, COM-интерфейсы, вопщем, всё эти тихие ужасы...
Если бы Дон Сайм (Don Syme) не стал разрабатывать F#, а всю эту энергию направил бы на доделку GHC.NET, у него наверняка всё получилось бы... :о)
Для приведённого выше кода на Хаскелле на C# придётся делать такое:
Код:
class Rec : Object
{
public string str;
public int num;
public bool flag;
public Rec(string s, int n, bool f)
{
this.str = s;
this.num = n;
this.flag = f;
}
public string ToString()
{
return "Rec { str = \"" + str + "\", num = " + num.ToString() +
", flag = " + flag.ToString() + " }";
}
}
На F# и то покрасивше:
Код:
type Rec = { str : string; num : int; flag : bool }
with
override x.ToString() =
"Rec { str = \"" + x.str + "\", num = " +
x.num.ToString() + ", flag = " + x.flag.ToString() + " }"
end;;
без ООП, правда, всё равно не обошлось (перегрузка метода ToString())...
Код:
> { str = "abc"; num = 1; flag = true }.ToString();;
val it : string = "Rec { str = \"abc\", num = 1, flag = True }"