Помощь новичкам


#1485

Да потому что я сам уже со всеми этими терминологическими игрищами запутался! )))) Думаю про одно, а пишу другое.Я там подправил.

Т.е. строки в реализации не ссылочные, но и не размерные. Как я помню, вы меж собой называете их “волшебными”. А какие типы еще обладают волшебством? Множества, кажется?

А если я подобным образом (присваивание и передача в процедуру) протестирую и другие типы данных - это будет достаточным основанием самостоятельно отнести их к размерному или ссылочному типу?


#1486

Тут я согласен. Но в Delphi тоже COW для строк работает.

Надо будет аккуратнее описать это в справке. Т.е. сказать, что в ряде случаев строка ведет себя как размерная, а в ряде - как ссылочная. И поддерживает модель COW.


#1487

У нас всё волшебное ))


#1488

Здесь надо договориться о терминологии, что называть размерным, а что - ссылочным типом. COW кстати появилась в какой-то момент времени для строк в Delphi, сделав их более эффективныыми в ряде случаев.

С некоторой точки зрения COW можно тоже считать особенностью реализации и на верхнем уровне не рассматривать.

Кто-то например считает, что если в C# - эта штуковина ссылочная, то и у нас - ссылочная. Но он не прав. Это порочный и тупиковый путь, ведущий в никуда.


#1489

А объясните простыми словами почему так получается, пожалуйста

begin
  var s := '123';
  var s1 := s;
  var s2 := '123';
  Swap(s1[1], s1[2]);
  Println(s, s1, s2);//213 213 213
end.

#1490

Вот пример проще:

procedure p1(var ch: char) :=
ch := '_';

begin
  var s := '123';
  var s1 := s;
  var s2 := '123';
  p1(s1[2]);
  Println(s, s1, s2);//1_3 1_3 1_3
end.

Строку не копирует, когда передаёт её символ в виде var-параметра. Я не совсем понимаю почему, но наверное ради какой то оптимизации.

@MrFresnel, @Gleb проверьте пожалуйста эту же программу в C#, будет ли там такое же творится.


#1491

В C# строки неизменяемые слава богу. Там такого нет.


#1492

Так значит это ошибка паскаля? Или всм C# вообще запрещает s[2] := '_' и передачу в виде var-параметров?


#1493

Ну архитектурный ляп паскаля. Строки не должны быть изменяемыми, да. Иначе видите, что будет творится.


#1494

Ну, тогда надо лишь добавить копирование строки перед передачей её символа в виде var-параметра, разве нет? Так же как во все остальных случаях, когда содержимое строки изменяется.


#1495

Я уже выше предложил вариант. Справка пишется для пользователя, причем, для пользователя любого уровня. Размерный тип или ссылочный, - об этом пользователю придется в любом варианте подумать, когда он дойдет до передачи и возврата параметров в подпрограммы, потому что зазубрить все возможные варианты для каждого типа очень сложно и даже глуповато как-то. Иными словами, я предложил посмотреть на типы с точки зрения конечного пользователя. Которому (по крайней мере, вначале) все равно, как там оно “внутри устроено”. Т.е. посмотреть, ведет себя тип как размерный или ссылочный. Соответственно на этом основании решить, куда его отнести. А как иначе? Может быть, в вузе можно по-другому, но если мы надеемся, что язык придет и в школы/колледжи, там иной уровень и учителей, и учеников. Им как-то попроще надо и однозначнее.

А как насчет VB.NET?

Sub Main()
   Dim s As String = "My own string"
   Mid(s, 4, 3) = "NET"
   Console.WriteLine(s)
   Dim m As String = Mid(s1, 8, 6)
   Console.WriteLine(s1)
End Sub

#1496

Изменяемость строк и COW – это еще можно понять и простить. :slight_smile: Меня вот больше всего напрягает следующая сомнительная оптимизация: при инициализации строковой переменной (не константы!) создается ссылка на уже существующую строку в куче, если такая уже есть (вместо создания новой).

Это легко может привести к трудно диагностируемым ошибкам, как в примерах выше с обработкой строки в подпрограмме:

begin
  var s1 := '111';
  var s2 := '111';
  s1.Equals(s2).Print //True -- зачем так делать???
end.

Это особенность платформы CLI или компилятора Паскаля? @ibond @Admin Можно ли это как-то запретить и оставить только для инициализации именно констант?


#1497

А в чем проблема?

begin
  var s1 := '111';
  var s2 := '111';
  s1.Equals(s2).Println; //True
  s2[1] := '2';
  Println(s1, s2, s1.Equals(s2)) // 111 211 False
end.

#1498

В том-то и проблема – смешанное поведение! Гермафродит :slight_smile:

Это называется “протечка абстракций”. Это проблема неустранимая (без нарушения совместимости).


#1499

Проблемный пример кода приведен выше (с передачей и обработкой одной из строк-близнецов в подпрограмме). Это крайне неочевидная ситуация для программиста – литеральные строки могут случайно совпасть по значению и незаметно стать сиамскими близнецами с побочным эффектом.


#1500

Если тут имеет место моделирование поведения в каком-то другом языке - конечно неустранимая.

А вы попробуйте такое написать - и посмотрим.


#1501

Причем тут другие языки? Неустранимая – на уровне строгой классификации типа. Гибрид – он и в Африке гибрид.

Чего тут пробовать и смотреть? Наличие скрытого побочного эффекта у стандартного и широкораспространенного типа в языке (к тому же недокументированного эффекта) – это очень плохо. Потенциальный data loss bug на ровном месте.


#1502

Пока это только разговор. Теоретизация. Мы уже видели. что есть тут вещи, которые в обычные теории не укладываются. Поэтому нужен эксперимент. Т.е. код.

Притом, что если бы не ставилось требований совместимости c предшественниками, можно было сделать строки такими, какими их хочется видеть.


#1503

Так я и сказал, что неустранимая без нарушения совместимости. Вы только раньше переформулировали это по-своему, ссылаясь на моделирование другого языка.

В чем ваш контраргумент? В том, что это гипотетически редкая ситуация, с которой еще надо умудриться столкнуться? Да, к счастью, редкая. У меня пока не было. Но я считаю, раз потенциальная побочка есть, её как минимум следует описать в Справке.

А еще лучше – устранить. Пока вроде бы единственный проблемный случай – использование переменной-строки с индексным свойством в качестве фактического параметра при передаче её значения в подпрограмму по ссылке (var). В этом случае компилятор мог бы делать копию строки и такой побочки бы не было. Правда, это замедлит работу со Swap(<char>,<char>) и ему подобным.

Второй вариант решения – не создавать изначально строковых переменных - “сиамских близнецов” (можно оставить это только для констант) – если это вообще реально сделать на уровне компилятора.

Или, в конце концов, просто ограничиться описанием обсуждаемой проблемы в хэлпе (с примером кода).

Вопрос остается открытым, как это объяснять достаточно просто, но строго, и без путаницы и противоречий. Тем более новичкам. Вводить дополнительное понятие гибридного типа?


#1504

Не скомпилируется даже отдельный фрагмент с попыткой изменения символа. Хотя бы потому, что свойство или индексатор по ссылке не может быть передан.

namespace Test
{	
	class Program
	{	
		public static void Method(ref char x)
		{
			x = '_';
		}
		
		public static void Main(string[] args)
		{
			string s1 = "12";
			Method(ref s1[0]);
		}
	}
}

Выдаст при попытке компиляции:

Свойство, индексатор или динамический член не может передаваться как параметр с ключевым словом out или ref (CS0206) - C:\Users\Admin\Documents\SharpDevelop Projects\Test1\Test1\Program.cs:23,15