Выход из процедуры родителя

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Выход из процедуры родителя

Сообщение pda » 21.01.2015 15:25:29

Лекс Айрин писал(а):pda, а кто говорит, что FPC хорошо написан?

Плохо? ;-) Тогда можете посмотреть в исходники Delphi. Тоже плохо? Тогда перейдём в стан C/C++ с их return. Ядро Linux с пачками
Код: Выделить всё
if (!buffer)
      return -ENOMEM;

для вас тоже плохо написано? ;-)
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 21.01.2015 15:48:24

pda,С/С++ еще хуже написаны. Потому и ошибки вылезают пачками.

Собственно, по этому пишем-с на FPC.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Выход из процедуры родителя

Сообщение bormant » 21.01.2015 17:38:15

Лекс Айрин писал(а):забейте на Exit. Как правило, если он используется, то значит программист не очень хорошо проработал код в данном месте программы. Exit, это тот же Goto и, насколько мне известно, компилируется в команду безусловного перехода в бинарном коде.

такое ощущение, что программ на Фортране или Бейсике без структурных операторов вы не видели, поэтому применяете расхожие фразы о вреде Goto несколько не по назначению.
Если ошибся, извините, но с ощущением ничего не могу поделать.

PS. Неважно во что компилируется Exit, важно, что его действие ограничено одним именованным блоком кода.
Аватара пользователя
bormant
постоялец
 
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 21.01.2015 18:01:03

bormant Я не говорю, что Goto вреден сам по себе, и вполне могу представить ситуацию его использования. Но вот, как минимум, читабельность программы страдает. Плюс, если есть возможность написать так...
Код: Выделить всё
If Err>0 then
Begin
...
End
Else //лучше, конечно, неполный if, но FPC  возникают иногда ошибки :((
Begin end;

то почему я должен писать так?
Код: Выделить всё
If Err=0 then exit
Else
Begin
...
end;

Я как-то не привык сначала надевать шубу, а потом рубашку.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Выход из процедуры родителя

Сообщение pda » 21.01.2015 18:22:00

Лекс Айрин писал(а):почему я должен писать так?

Потому что сможете убрать три лишние строки (else, begin, end). А при наличии более сложных проверок в процедуре можно сократить её размер до двух раз.
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 21.01.2015 18:36:17

pda
1) не уберу. Наличие этой ветки косяк компилятора. Да и не три, а две.

2) Поиграв с порядком проверок, так же можно значительно сократить их количество. Плюс, возросшая читабельность.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Выход из процедуры родителя

Сообщение pda » 21.01.2015 18:45:13

Лекс Айрин писал(а):Наличие этой ветки косяк компилятора.


Лолшто? У вас не работает
Код: Выделить всё
If Err=0 then exit;


Лекс Айрин писал(а):Поиграв с порядком проверок, так же можно значительно сократить их количество.

Хотел бы посмотреть на случай if внутри case... :roll: А впрочем не надо. Я понимаю, что вы при любом раскладе предпочтёте наплодить if'ов...
Последний раз редактировалось pda 21.01.2015 18:54:11, всего редактировалось 1 раз.
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 21.01.2015 18:53:17

pda писал(а):Лолшто? У вас не работает


Не знаю. Никогда не требовалось. У меня неправильно работает неполный if...

pda писал(а):Хотел бы посмотреть на случай if внутри case...


у... это еще тот геморрой.... сейчас поищу... не... есть только Case внутри if

Код: Выделить всё
    procedure TMainForm.MenuOpenClick(Sender: TObject);
var
  Str: TStringList;
begin
  Str := TStringList.Create;
  if OpenDialog1.Execute then
  begin
    MyFile := OpenDialog1.FileName;
    Caption := MyFile + ':LexEditor';
    // ожидается выбор кодировки текста
    case OpenDialog1.FilterIndex of
      1:
      begin
                 {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines := Str;
      end;
      2:
      begin
                {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
      end;
      3:begin // *.* UTF8
                 {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines := Str;
      end;
      4:begin  // *.* Win1251
                {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
      end;
      else
      begin
      end;
    end;
  end
  else
  begin
  end;
  Str.Free;
  MainForm.ShellTreeView1.Path:=MainForm.OpenDialog1.InitialDir;
end;           

ЗЫ: постараюсь убрать этот код
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Выход из процедуры родителя

Сообщение pda » 21.01.2015 19:22:10

Лекс Айрин писал(а):У меня неправильно работает неполный if...

Вот это жесть, если честно.
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Re: Выход из процедуры родителя

Сообщение pupsik » 22.01.2015 02:08:44

по поводу последнего кода:
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    MyFile := OpenDialog1.FileName;
    Caption := MyFile + ':LexEditor';
    // ожидается выбор кодировки текста
    MainEditor.Lines := load_text(OpenDialog1.FilterIndex, MyFile)
  end else
  begin
////
  end;
  ShellTreeView1.Path := OpenDialog1.InitialDir;
end;

function TForm1.load_text(a_value: integer; const a_file: string): TStrings;

function get_path(a_name : string) : string;
begin
  result := ConvertEncoding(a_name, EncodingUTF8, GetDefaultTextEncoding);
end;

var
  Str: TStringList;
begin
  Str := TStringList.create;
  Str.LoadFromFile(get_path(a_file));
  case a_value  of
    1 : result := Str;
    2 : result.Text := CP1251ToUTF8(Str.Text);
    3 : result := Str;
    4 : result.Text := CP1251ToUTF8(Str.Text);
  end;
  Str.free;
end;
"рабочесть" не проверял (мог спутать с именем файла (не хочу в виртуалку)..). А вот момент повторения ... повторения - интересен :?

по поводу exit В принципе им пользоваться можно, можно и без него. А разница то в чем (у вас в goto). Вспоминая учебники и туториалы там этим грешитсо по полной и никто не жаловался. Иной раз советуют его пользовать для избежания не нужного прохода. Пример из книги по алгоритмам (первый попавшийся):
Код: Выделить всё
function TDTListIndexOf(aList : TList; aItem : pointer;
                        aCompare : TtdCompareFunc) : integer;
var
  Inx : integer;
begin
  for Inx := 0 to pred(aList.Count) do
    if (aCompare(aList.List^[Inx], aItem) = 0) then begin
      Result := Inx;
      Exit;
    end;
  Result := -1;
end;
И опять же в книге вполне аргументировано использование данного гоуту :)

inline хм.. если не ошибаюсь: сие дело наследие дельфина, а само оно из си?

У меня неправильно работает неполный if...
:shock: весьма странно. Лазарь и фпс грешат на многое. Но вот на такое - впервые читаю (но все в мире возможно). У меня он всегда адекватно "реагировал".

п.с.
А вот тут не понял:
...то посчитал более перспективным работать с нуля.
и
Собственно, по этому пишем-с на FPC.
Весьма странно. Т.е. вы заново фпс переписываете или э...э.
Кстати sign уже ответил на вопрос. Единственное что необходимо вопрошающему - понять: зачем нужны функции, процедуры и как ими пользоваться.
pupsik
энтузиаст
 
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13

Re: Выход из процедуры родителя

Сообщение SSerge » 22.01.2015 06:23:47

Лекс Айрин писал(а):не... есть только Case внутри if

Код: Выделить всё
        procedure TMainForm.MenuOpenClick(Sender: TObject);
    var
      Str: TStringList;
    begin
      Str := TStringList.Create;
      if OpenDialog1.Execute then
      begin
        MyFile := OpenDialog1.FileName;
        Caption := MyFile + ':LexEditor';
        // ожидается выбор кодировки текста
        case OpenDialog1.FilterIndex of
          1:
          begin
                     {$IFDEF MSWINDOWS}
            Str.LoadFromFile(UTF8ToSys(MyFile));
                     {$ENDIF}
                     {$IFDEF LINUX}
            Str.LoadFromFile(MyFile);
    {$ENDIF}
            MainEditor.Lines := Str;
          end;
          2:
          begin
                    {$IFDEF MSWINDOWS}
            Str.LoadFromFile(UTF8ToSys(MyFile));
                     {$ENDIF}
                     {$IFDEF LINUX}
            Str.LoadFromFile(MyFile);
    {$ENDIF}
            MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
          end;
          3:begin // *.* UTF8
                     {$IFDEF MSWINDOWS}
            Str.LoadFromFile(UTF8ToSys(MyFile));
                     {$ENDIF}
                     {$IFDEF LINUX}
            Str.LoadFromFile(MyFile);
    {$ENDIF}
            MainEditor.Lines := Str;
          end;
          4:begin  // *.* Win1251
                    {$IFDEF MSWINDOWS}
            Str.LoadFromFile(UTF8ToSys(MyFile));
                     {$ENDIF}
                     {$IFDEF LINUX}
            Str.LoadFromFile(MyFile);
    {$ENDIF}
            MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
          end;
          else
          begin
          end;
        end;
      end
      else
      begin
      end;
      Str.Free;
      MainForm.ShellTreeView1.Path:=MainForm.OpenDialog1.InitialDir;
    end;           


ЗЫ: постараюсь убрать этот код


Осподе, кошмар какой. :twisted:
Еще тут кто-то мне пишет, что я есмь центральный индусский говнокодер сайта.

Итак:
1. Не проверяется, как закрыто окно выбора файлов. В случае отказа через cancel myFileName:= и так далее
2. Зачем в case пустой блок и ветка else? Тоже из тех же соображений, что "неполный if не работает" (С)
3. по поводу этого:

Код: Выделить всё
{$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}


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

----------
1. и вот сказал Создатель - возврат результата из функции должен осуществляться путем присвоения результирующего значения идентификатору функции. И было сделано. И показалось - это хорошо.
2. науськиваемый врагом Рода человеческого Программер научился копировать куски своего и чужога кода, получил кучу ошибок копиляции и взмолился - спаси, Отче, ибо! И возникла псевдопеременная Result. И стало такъ.
3. и прошли времена Паскалей, и Программер взмолился: пашто, Отче, во всех языкахъ программирований ихъ программеры для выхода изнутрей функции пишут один! оператор return xxx, а я, труъ программер Паскаля должен оформить блок begin-end, присвоить значение православной переменной Result, и вызвать функцию Exit, что аж четыре строки! Дай, о Отче! И возникла форма Exit(returnCode). И стало такъ.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Выход из процедуры родителя

Сообщение sign » 22.01.2015 06:44:36

Лекс Айрин писал(а): Exit, это тот же Goto и, насколько мне известно, компилируется в команду безусловного перехода в бинарном коде.

И пусть себе.
Ассемблер, он вообще, сплошь и рядом переходы.

А exit однозначно показывает, что я покидаю функцию (процедуру). И при этом могу тут же указать, с каким результатом.
Весьма удобно и часто намного упрощает функцию (процедуру).

Вот маленький пример, мне именно так писать удобнее, а потом читать удобнее.
Код: Выделить всё
procedure TIcon.SetStatus(AValue: TStatus);
begin
  if FStatus = AValue then Exit;
  if (FStatus = csFocus) and (AValue = csHot) then Exit;
  FStatus := AValue;
  if (AValue = csFocus) and (Parent is TBranch) then TBranch(Parent).IconFocus := Self;
end;


Добавлено спустя 9 минут 42 секунды:
Лекс Айрин писал(а):у... это еще тот геморрой.... сейчас поищу... не... есть только Case внутри if
Код: Выделить всё
    procedure TMainForm.MenuOpenClick(Sender: TObject);
var
  Str: TStringList;
begin
  Str := TStringList.Create;
  if OpenDialog1.Execute then
  begin
    MyFile := OpenDialog1.FileName;
    Caption := MyFile + ':LexEditor';
    // ожидается выбор кодировки текста
    case OpenDialog1.FilterIndex of
      1:
      begin
                 {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines := Str;
      end;
      2:
      begin
                {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
      end;
      3:begin // *.* UTF8
                 {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines := Str;
      end;
      4:begin  // *.* Win1251
                {$IFDEF MSWINDOWS}
        Str.LoadFromFile(UTF8ToSys(MyFile));
                 {$ENDIF}
                 {$IFDEF LINUX}
        Str.LoadFromFile(MyFile);
{$ENDIF}
        MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
      end;
      else
      begin
      end;
    end;
  end
  else
  begin
  end;
  Str.Free;
  MainForm.ShellTreeView1.Path:=MainForm.OpenDialog1.InitialDir;
end;           



Для меня жуть!
Я вот так бы это написал (не вдаваясь в сам алгоритм, а только выкинув лишние else).
Код: Выделить всё
procedure MenuOpenClick(Sender: TObject);
var Str: TStringList;
begin
  if not OpenDialog1.Execute then Exit;
  Str := TStringList.Create;
  try
    MyFile := OpenDialog1.FileName;
    Caption := MyFile + ':LexEditor';
    // ожидается выбор кодировки текста
    case OpenDialog1.FilterIndex of
        1: begin
                   {$IFDEF MSWINDOWS}
             Str.LoadFromFile(UTF8ToSys(MyFile));
                   {$ENDIF}
                   {$IFDEF LINUX}
             Str.LoadFromFile(MyFile);
                   {$ENDIF}
             MainEditor.Lines := Str;
           end;
        2: begin
                  {$IFDEF MSWINDOWS}
             Str.LoadFromFile(UTF8ToSys(MyFile));
                   {$ENDIF}
                   {$IFDEF LINUX}
             Str.LoadFromFile(MyFile);
                   {$ENDIF}
             MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
           end;
        3: begin // *.* UTF8
                   {$IFDEF MSWINDOWS}
             Str.LoadFromFile(UTF8ToSys(MyFile));
                   {$ENDIF}
                   {$IFDEF LINUX}
             Str.LoadFromFile(MyFile);
                   {$ENDIF}
             MainEditor.Lines := Str;
           end;
        4: begin  // *.* Win1251
                  {$IFDEF MSWINDOWS}
             Str.LoadFromFile(UTF8ToSys(MyFile));
                   {$ENDIF}
                   {$IFDEF LINUX}
             Str.LoadFromFile(MyFile);
                   {$ENDIF}
             MainEditor.Lines.Text := CP1251ToUTF8(Str.Text);
           end;
    end;
    MainForm.ShellTreeView1.Path:=MainForm.OpenDialog1.InitialDir;
  finally
    Str.Free;
  end;
end;


Добавлено спустя 2 минуты 57 секунд:
pupsik писал(а):по поводу последнего кода:
Пример из книги по алгоритмам (первый попавшийся):
Код: Выделить всё
function TDTListIndexOf(aList : TList; aItem : pointer;
                        aCompare : TtdCompareFunc) : integer;
var
  Inx : integer;
begin
  for Inx := 0 to pred(aList.Count) do
    if (aCompare(aList.List^[Inx], aItem) = 0) then begin
      Result := Inx;
      Exit;
    end;
  Result := -1;
end;

И что хорошо, можно написать вот так (я так сейчас всегда делаю)-

Код: Выделить всё
function TDTListIndexOf(aList : TList; aItem : pointer; aCompare : TtdCompareFunc) : integer;
var Inx : integer;
begin
  for Inx := 0 to pred(aList.Count) do
    if (aCompare(aList.List^[Inx], aItem) = 0) then Exit(Inx);
  Result := -1;
end;
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 22.01.2015 11:19:55

pupsik писал(а):Весьма странно. Т.е. вы заново фпс переписываете или э...э.


Или. Паскалеподобный язык. Но пока идет период накопления материала.

SSerge писал(а):2. Зачем в case пустой блок и ветка else? Тоже из тех же соображений, что "неполный if не работает" (С)


путаница между else от if и case. Лучше уж прописать явно.

SSerge писал(а):Не проверяется, как закрыто окно выбора файлов. В случае отказа через cancel myFileName:= и так далее


Просто для программы это неважно.

sign писал(а):Я вот так бы это написал (не вдаваясь в сам алгоритм, а только выкинув лишние else).


Вот как раз для отсутствия try и finally причина того, что у меня есть лишние ветки. Я просто здесь делаю обработку сразу, а не допускаю возникновение ошибки. Которую потом еще как-то надо обработать! Вот когда у меня будет 10 и более вариантов, тогда есть смысл в отдельной процедуре.

SSerge писал(а):Но, ёпта, повторять это 100500 раз зачем? Сделать свою отдельную процедуру, в которую запихать чтение, не судьба? Не говоря уж о том, что результат чтения - опять не проверяется.


В данном случае нерентабельно заводить процедуру. А что результат чтения не проверяется... так есть стандартная проверка -- зачем ее дублировать?

В любом случае, этот код мне не нравился еще когда я скопировал.
И я его переделаю, потому что он страшен.

sign писал(а):И что хорошо, можно написать вот так (я так сейчас всегда делаю)


Я бы написал так:
Код: Выделить всё
function TDTListIndexOf(aList : TList; aItem : pointer; aCompare : TtdCompareFunc) : integer;
var Inx : integer;
begin
Result := -1; 
for Inx := 0 to pred(aList.Count) do
    if (aCompare(aList.List^[Inx], aItem) = 0) then Result := Inx;
 
end;


Вуаля, куда-то Exit делся. И в случае внесения дополнительных проверок я буду уверен, что неприсвоенного результата не будет.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Выход из процедуры родителя

Сообщение SSerge » 22.01.2015 11:43:20

Лекс Айрин писал(а):Я бы написал так:

Вуаля, куда-то Exit делся. И в случае внесения дополнительных проверок я буду уверен, что неприсвоенного результата не будет.


...и получил бы неверный результат возврата функции, потому что присваивание result значения не приводит ни к выходу из цикла, ни к завершению процедуры
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Выход из процедуры родителя

Сообщение Лекс Айрин » 22.01.2015 11:52:59

SSerge Упс... А зачем здесь For? Попробуем тогда так...

Код: Выделить всё
function TDTListIndexOf(aList : TList; aItem : pointer; aCompare : TtdCompareFunc) : integer;
var Inx : integer;
begin
        Result := -1;
        inx:=0;
        while (aCompare(aList.List^[Inx], aItem) = 0) do
        Begin
                 inx:=inx+1
        End;
end;
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Пред.След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 231

Рейтинг@Mail.ru