Замечания и предложения

Конкретнее выражайтесь, это ничего не говорит.

И - та функция всё равно дубль, оригиналы всех для работы с путями к файлам - в классе System.IO.Path.

Наверное вы её неправильно использовали

Вот к примеру небольшой код, использующий стороннюю библиотеку для распаковки архива. Исходник лежит в папке с игрой Skyrim.

{$reference 'SharpCompress.dll'}
uses SharpCompress, SharpCompress.Archives;
begin
  try
    var archive: SharpCompress.Archives.IArchive := SharpCompress.Archives.ArchiveFactory.Open(ExtractFilePath(GetEXEFileName) + 'Skyrim\Updates\Enhanced_Blood_Textures_LITE.rar', nil);
    var EO := new SharpCompress.Common.ExtractionOptions;
    EO.ExtractFullPath := true;
    EO.Overwrite := true;
    foreach var entry in archive.Entries do
      if not entry.IsDirectory then entry.WriteToDirectory(ExtractFilePath(GetEXEFileName) + 'Mod Organizer\mods\', EO);
  except
    on System.DivideByZeroException do 
      writeln('Деление на 0');
    on e: System.IndexOutOfRangeException do
      writeln(e.Message);
    on System.FormatException do
      writeln('Неверный формат ввода');
  else writeln('Какое-то другое исключение');
  end;
end.

Если в настройках не отрубить функцию “Выходные файлы генерировать в директорию такую-то”, то программа будет сыпать ошибку:

Ошибка времени выполнения: System.IO.FileNotFoundException: Не удалось загрузить файл или сборку “SharpCompress, Version=0.23.0.0, Culture=neutral, PublicKeyToken=afb0a02973931d96” либо одну из их зависимостей. Не удается найти указанный файл. Стек: в 1.Program.$Main() в 1.Program.Main()

1 лайк

По моему уже был разговор про это здесь. Но разработчики то ли не прочитали, то ли проигнорили… В общем сделал issue, теперь точно заметят:

Не помню, предлагалось уже или нет…

function ToDigits(self: integer): sequence of integer; extensionmethod;
begin
  if self<0 then
    if self=integer.MinValue then
    begin
      yield 2;
      self := 147483648;
    end else
      self := -self;
  
  var d := 1;
  var m := self div 10;
  while d<=m do d *= 10;
  
  while d <> 0 do
  begin
    yield System.Math.DivRem(self,d,self);
    d := d div 10;
  end;
  
end;

begin
  (12345).ToDigits.Println;
  (10000).ToDigits.Println;
  integer.MaxValue.ToDigits.Println;
  (-12345).ToDigits.Println;
  integer.MinValue.ToDigits.Println;
end.

(ну и по аналогии с int64 и может BigInteger)

Подтолкнуло написать это: http://www.cyberforum.ru/pascalabc-net/thread2551911.html#post14087426

Предложение однозначно хорошее, на мой взгляд, поэтому:

Хорошо бы было (с моей точки зрения), если бы в PascalABC.NET:

  • поддерживались списки ToDo
  • интеграция с Git и возможность работать с GitHub
  • средства рефакторинга кода

Я не настаиваю и вряд ли стал бы по следующей причине - PascalABC.NET не гонится за такими гигантами, как Visual Studio/Rider (хотя, некоторые вещи бывает просят перетянуть из них и сюда), также ориентирован на начинающих.

Если бы (возможно, в будущем) данный проект решил бы развиваться по пути профессиональных IDE, то я бы предложил бы эти два нововведения (хотя, очень вероятно, что заниматься ими начали сами разработчики и без моего напоминания). В то же время, тогда бы встал вполне понятный вопрос: Зачем это всё нужно в IDE, если ниша данного языка - начинающие?. Да, конечно, иметь дополнительный функционал, который может пригодится - хорошо, но ведь, нишу “производственную” уже заняли другие IDE, такие как Visual Studio и Rider и насколько будет он (функционал) использоваться в PascalABC.NET - неизвестно (для ответа на данный вопрос надо чётко знать потребности пользователей), в то время как - это трата времени (вполне возможно впустую) разработчиков, которое они бы могли потратить на увеличение стабильности работы IDE (улучшение Intellisence, например).

Любые навески к IDE затрудняют работу начинающих (этим разные Студии всегда отпугивают новичков). Потому что видишь непонятный функционал и начинаешь думать, вдруг он нужен тебе, вдруг он - обязательная вещь для работы?. Ну т.е. если мы впервые садимся за управление современного автомобиля, поражает обилие разных кнопочек, ручечек и сигнальчиков. При этом мы догадываемся, что поехать можно, запустив двигатель и нажав на педальку, а вот надо ли использовать остальное и как - это лишь отвлекает.

1 лайк

Или, взять интерфейс SharpDevelop, он, по сравнению с интерфейсом PascalABC.NET перегружен (хотя, проще IDE для C# я не встречал):

Тут следует добавить ещё ремарку. Если бы разработчики PascalABC.NET действительно взяли такой курс, то несомненно это бы поменяло аудиторию PascalABC.NET в какой-то степени. И, конечно, это уже был бы иной PascalABC.NET, рассчитанный на более продвинутых пользователей, точнее часть людей могла бы просто перестать пользоваться этой IDE, потому что она стала бы больше походить на Visual Studio своей насыщенностью кнопочек. Надо ли это нам? - вполне оправданно задавать себе такой вопрос разработчикам. Ведь, если не PascalABC.NET, то что послужит первой ступенью в изучении языка Pascal?.. (Free Pascal - вариант, но, насколько помню, его интерфейс более “отталкивающий” для новичков.)

И, конечно, предлагаемые мною возможности можно было бы реализовать дополнениями. Тогда бы проблем с насыщенностью кнопочкам интерфейса IDE по умолчанию не возникало, но:

Мне кажется, стОит в этом случае говорить о том, чтобы интегрировать консольный компилятор и средства Intellisense в какой-то известный расширяемый редактор. Например. в VS Code.

2 лайка

Так-с, пока я пытался оставить замечание по среде разработки, у меня появились замечания по сайту:

  • если при регистрации выделить мышью текст в поле пароля, например, то окно регистрации закрывается, это очень сильно раздражает
  • раздражает невозможность ввести слабый пароль. Можно было бы сделать просто предупреждение, с которым можно было согласиться и продолжить, либо изменить слабый пароль
  • после регистрации навязчивая просьба посмотреть уведомление. И даже если посмотреть его, то эта полупрозрачная “пелена” на экране остается и все продолжает предлагать посмотреть уведомление. Убирается перезагрузкой. Я не думаю, что это фича

Теперь по IDE: Режим автозавершения кода работает странно В настройках стоит конвертация Tab в 4-е пробела. Если написать “begin” и нажать Enter, произойдет автозавершение и между операторными скобками появится отступ в 2-а пробела. В редакторе стоит моноширинный шрифт, благодаря чему можно заметить, что ставится отступ из 2-х пробелов:

Я понимаю, что это две разные вещи (конвертация tab и отступ), но почему бы отступ не делать по кол-ву пробелов в конвертации?!

1 лайк

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

Может есть смысл добавить перегрузки с параметрами:

  1. function string.replace(oldvalue:string, newvalue:string, count:cardinal):string;
  2. function string.replace(oldvalue:string, newvalue:string, count:cardinal, position:cardinal):string;

Заранее прошу простить ежели не доглядел и уже было.

Вы сами сказали, что это разные вещи. Мы считаем правильным форматирование с отступом в 2 пробела.

Возможно, стоит, прописать где-нибудь это явно, например, прямо в настройках, если менять не собираетесь, но и не хотите снова таких вопросов от пользователей.

Имеется следующая задача: %D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA

Ее можно решить как в традиционном, так и в функциональном стиле. Сравним.

begin
  var n := ReadInteger;
  var a := ReadArrInteger(n);
  // функциональный стиль
  a.Select((v, i) -> (v, i))
      .Where(t -> Abs(t[0]) mod 10 = 7)
      .Select(t -> t[1] + 1)
      .Sum
      .Println;
  // традиционный стиль    
  var s := 0;
  for var i := 0 to a.High do
    if Abs(a[i]) mod 10 = 7 then
      s += i + 1;
  s.Println;    
end.

Функциональное решение по длине не короче традиционного, но выглядит существенно сложнее и требует определенных добавочных знаний.

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

Если индекс один - у нас есть чудесные средства FindIngex и FindIndexLast. Но почему же нет FindIndices? Тогда у нас была бы возможность решить такую задачу куда понятнее и красивее:

begin
  var n := ReadInteger;
  var a := ReadArrInteger(n);
  a.FindIndices(t -> Abs(t) mod 10 = 7)
      .Sum(i -> i + 1)
      .Println
end.

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

Может быть, имеет смысл подумать над таким расширением? Было бы отличное симметричное дополнение для .FindAll.

2 лайка

В функциональном стиле - я бы решал так:

begin
  var a := ReadArrInteger(ReadInteger);
  
  a.Numerate
    .Where(t-> Abs(t[1]) mod 10 = 7 )
    .Sum(t->t[0]).Println
  ;
  
end.

Функции нахождения всех индексов таки много где пригодилась бы. Но если делать - лучше называть FindAllIndices, раз это индексный вариант FindAll, и чтоб визуально проще было отличить от FindIndex.

Сразу пример реализации и использования:

function FindAllIndeces<T>(self: sequence of T; pred: T->boolean; from: integer): sequence of integer; extensionmethod;
begin
  foreach var a in self do
  begin
    if pred(a) then yield from;
    from += 1;
  end;
end;

// потому что yield всё ещё не совместимо с параметрами по-умолчанию
function FindAllIndeces<T>(self: sequence of T; pred: T->boolean): sequence of integer; extensionmethod := self.FindAllIndeces(pred, 0);

begin
  var a := ReadArrInteger(ReadInteger);
  
  a.FindAllIndeces(x-> Abs(x) mod 10 = 7, 1)
    .Sum.Println
  ;
  
end.
2 лайка

Ну, есть оно - вы же книгу писали:

begin
  ReadArrInteger(ReadInteger).Indices(t -> Abs(t) mod 10 = 7).Sum(i -> i + 1).Println
end.
2 лайка

Вот же… Когда писал код, почему-то Intellisence упорно не хотел вариант с лямбдой показать. Я и подумал… Разве все упомнишь? Все же какое счастье, что оно уже есть))))

2 лайка

Обновился до сборки 2281 от 2112. Предыдущую сборку проверить не успел. Что-то случилось с автозавершением кода; во всяком случае, оно меня буквально изнасиловало на условных операторах. В ветке then после оператора по нажатию Enter упорно втыкается точка с запятой. Может, кому-то нравится этот С-подобный синтаксис, но при большом количестве условных операторов, особенно сложных с else if, постоянно нырять на предыдущую строку и затирать точку с запятой - ну это может достать очень сильно!

В общем, я был бы очень благодарен, если убрать автовставку символа “;” после then <оператор>. Ибо достало реально! На самом деле таких неполных if, где ветка else отсутствует, статистически не должно быть много в программах.

%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA

Авто завершение кода ждёт от вас что если else будет - то на строчке с оператором, а не на следующей. Определить, собираетесь ли вы ставить else на следующей строке - невозможно. А обычно ; после оператора таки необходимо.