2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу 1, 2, 3, 4, 5, 6  След.
 
 Сравнение двух стилей программирования
Сообщение12.12.2012, 20:26 
Аватара пользователя
Всем доброго времени суток.

Краткая предыстория.
Я помаленьку увлекаюсь программированием уже много лет, с разной интенсивностью.
Соответственно как-то уже выработал привычки по написанию хорошего кода.
А в этом году поступил в крупный технический ВУЗ, на "CS"-специальность.
И столкнулся с массой людей, которые код пишут первый раз и потому пишут его "как могут".
Что заставило меня несколько задуматься о том, насколько ценны те принципы, которые я соблюдаю, уже на задумываясь об их смысле.

Представляю на суд посетителям этого форума два варианта решения простейшей задачи - построить очередь в динамической памяти, вывести, удалить. Оба на Delphi Pascal.

Мой:
код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
program list1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  pe=^element;
  element=record
    value: integer;
    next: pe;
  end;

var first, last, q: pe;
    x: integer;

procedure add(x: integer; var last: pe);
var t: pe;
begin
  New(t);

  t^.value:=x;
  t^.next:=nil;
  last^.next:=t;

  last:=t;
end;

procedure clear(var first: pe);
var t: pe;
begin
  while first<>nil do
    begin
      t:=first;
      first:=first^.next;
      Dispose(t);
    end;
end;

begin

  WriteLn('Input numbers:');
  ReadLn(x);

  New(first);
  first^.value:=x;
  first^.next:=nil;
  last:=first;

  ReadLn(x);
  while x<>0 do
    begin
      add(x, last);
      ReadLn(x);
    end;

  q:=first;
  while q<>nil do
   begin
    Write(q^.value, ' ');
    q:=q^.next;
   end;

  ReadLn;
  clear(first);

end.
 


Не мой:
код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
program list_zl;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type pe=^element;
     element=record
      value: integer;
      next: pe;
     end;

var
    first,last,q,t: pe;
    x: integer;

begin
  writeln('Input numbers:');
  ReadLn(x);

  New(first);
  first^.value:=x;
  last:=first;

  ReadLn(x);
  while x<>0 do
    begin
      New(last^.next);
      last:=last^.next;
      last^.value:=x;

      ReadLn(x);
    end;
  last^.next:=nil;

  q:=first;
  while q<>nil do
    begin
      write(q^.value,' ');
      t:=q;
      q:=q^.next;
      dispose(t);
    end;

 ReadLn;

end.
 


Второй почти в полтора раза короче. :\
Думаю, разницу в организации кода объяснять не надо, всё очевидно.

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 22:09 
Для выполнения учебных задач вполне хватит и второго. Однако при написании более-менее больших программ лучше пользоваться первым (по целому ряду причин). А выработать навыки написания хорошо структурированного кода можно при выполнении учебных задач. :D
Однако Вы остановились зачем-то на полпути. Код можно сделать еще вдвое длиннее и на порядок структурированнее (прошу прощения за возможные ошибки, на Pascal не писал уже очень давно, проверить работоспособность кода не могу):
код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
program ListOperations;

{$APPTYPE CONSOLE}

uses
        SysUtils;

type

        PElement = ^TElement;
       
        TElement =
                record
                        value : Integer;
                        nextElement : PElement;
                end;
               
        TList =
                record
                        firstElement : PElement;
                        lastElement : PElement;
                end;

var
        list : TList;


procedure InitList(var list : TList);
begin
        list.firstElement = nil;
        list.lastElement = nil;
end;

procedure AddElement(var list : TList; value : Integer);
var
        newElement : PElement;
begin
        New(newElement);
        newElement^.value := value;
        newElement^.nextElement := nil;
        with list do
        begin
                if firstElement = nil then
                        firstElement := newElement
                else
                        lastElement^.nextElement := newElement;
                lastElement := newElement;
        end;
end;

procedure ReadList(var list : TList);
var
        value : Integer;
begin
        WriteLn('Input list elements:');
        ReadLn(value);
        while value <> 0 do
        begin
                AddElement(list, value);
                ReadLn(value);
        end;
end;

procedure WriteList(const list : TList);
var
        element : PElement;
begin
        Writeln('List elements:');
        element := list.firstElement;
        while element <> nil do
        begin
                Write(element^.value, ' ');
                element := element^.nextElement;
        end;
        Writeln;
end;

procedure ClearList(var list : TList);
var
        element : PElement;
begin
        with list do
        begin
                while firstElement <> nil do
                begin
                        element := firstElement;
                        firstElement := firstElement^.nextElement;
                        Dispose(element);
                end;
                lastElement = nil;
        end;
end;

begin
        InitList(list);
        ReadList(list);
        WriteList(list);
        ReadLn;
        ClearList(list);
end.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 22:54 
Аватара пользователя
Впечатлён. Ошибок, кстати, почти нет, только в трёх местах "=" вместо ":=".
Скажите, Вы профессиональный программист? (:

(Оффтоп)

Кстати, я бы поспорил с внесением добавления первого элемента в цикл.
Это же создаст условие, которое будет проверяться каждый раз при выполнении тела цикла, но выполнится только единожды, что не круто.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 23:09 
shau-kote в сообщении #657741 писал(а):
Ошибок, кстати, почти нет, только в трёх местах "=" вместо ":=".
Хорошо хоть == на = в условии успел поменять.
shau-kote в сообщении #657741 писал(а):
Скажите, Вы профессиональный программист? (:
Раз ошибки есть, значит непрофессиональный. :-)
shau-kote в сообщении #657741 писал(а):
Это же создаст условие, которое будет проверяться каждый раз при выполнении тела цикла, но выполнится только единожды, что не круто.
В целом нехорошо, но и анализировать производительность до появления проблем с нею не слишком хорошо (по крайней мере, в такого рода программах). В данном случае выполнение единственного лишнего оператора рядом с заведомо более долгой операцией ввода не скажется на ней никак.
А уж предыдущий вариант, когда введенный первым ноль попадал в список вопреки всякой логике, заведомо хуже, поскольку вводит и пользователей программы, и пользователей кода в ненужные заблуждения.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 23:20 
Аватара пользователя
EtCetera в сообщении #657753 писал(а):
А уж предыдущий вариант, когда введенный первым ноль попадал в список вопреки всякой логике, заведомо хуже, поскольку вводит и пользователей программы, и пользователей кода в ненужные заблуждения.

Предполагалось, что будет хотя бы один элемент.
В любом случае, нет проблем обрамить добавление первого элемента проверкой того, является ли первое введённое число нулём.
Хотя, не могу не согласится с Вами о том, что причин беспокоится по поводу производительности всё же нет.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 23:37 
Аватара пользователя

(Оффтоп)

А в procedure add никто не хочет last^.next на nil проверить? А то в чём смысл структурировать программу, если получающиеся куски всё равно полагаются друг на друга...

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение12.12.2012, 23:55 
Аватара пользователя

(Оффтоп)

Нет, не хочу. (:
Потому что можно очень много чего проверять. Добавить ещё возвращение кода ошибки.
А можно просто полагать, что программист передаёт подпрограмме корректные данные.
В противном случае он ССЗБ, как говорится.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 00:16 

(Оффтоп)

Барьерный элемент всандалить в конец, и все, можно уже STL-подобный iterator делать.

shau-kote в сообщении #657777 писал(а):
А можно просто полагать, что программист передаёт подпрограмме корректные данные.
В противном случае он ССЗБ, как говорится.

О, я встречался с одной библиотекой, которая никак не валидировала входные параметры — впечатления очень не очень.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 00:38 
Аватара пользователя

(Оффтоп)

shau-kote в сообщении #657777 писал(а):
Потому что можно очень много чего проверять.

В идеале да. А тут всего лишь precondition процедуры, такой весь из себя очевидный и единственный.

shau-kote в сообщении #657777 писал(а):
А можно просто полагать, что программист передаёт подпрограмме корректные данные.

Вот этим и отличается учебное программирование от реального. Ваши "привычки по написанию хорошего кода" должны быть именно в этом, а не в наведении внешнего глянца.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 00:53 
Аватара пользователя

(Оффтоп)

Хорошо, что вы предлагаете делать, если last^.next<>nil?
А если недостаточно памяти для создания нового элемента? Тоже, в общем-то, precondition процедуры.
А если число, переданное в процедуру, нельзя без потерь преобразовать к типу value?

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 01:11 
shau-kote в сообщении #657789 писал(а):
Хорошо, что вы предлагаете делать, если last^.next<>nil?
Вставлять в середину списка.
shau-kote в сообщении #657789 писал(а):
А если недостаточно памяти для создания нового элемента?
Возвращать ошибку наиболее подходящим способом, я не помню, как в Паскале принято.
shau-kote в сообщении #657789 писал(а):
А если число, переданное в процедуру, нельзя без потерь преобразовать к типу value?
Так ведь у вас аргумент уже соответствующего типа.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 01:28 
Аватара пользователя
venco в сообщении #657791 писал(а):
Вставлять в середину списка.

Хм. Ну, хорошо, согласен.
Хотя, учитывая, что первоначальная логика работы процедуры была "добавить элемент в конец списка", я бы предпочёл, чтобы она вернула ошибку.

venco в сообщении #657791 писал(а):
Возвращать ошибку наиболее подходящим способом, я не помню, как в Паскале принято.

Да никак особо не принято.
Надо либо делать функцию, либо вводить дополнительный параметр.
И то, и то неплохо загромождает как основную программу, так и подпрограмму.
А первый вариант к тому же усложняет создание функций, работающих со списком. (И также могущих попадать в ситуации, когда необходимо вернуть ошибку.)

venco в сообщении #657791 писал(а):
Так ведь у вас аргумент уже соответствующего типа.

Да, но с учётом довольно слабой типизации Pascal'я, ничто не помешает передать в процедуру какой-нибудь longint, значение в котором ну никак не будет помещаться в поле value типа integer.
Что, однако, не помешает программу его туда засунуть. С плачевным результатом, само собой.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 02:15 
shau-kote в сообщении #657794 писал(а):
venco в сообщении #657791 писал(а):
Так ведь у вас аргумент уже соответствующего типа.

Да, но с учётом довольно слабой типизации Pascal'я, ничто не помешает передать в процедуру какой-нибудь longint, значение в котором ну никак не будет помещаться в поле value типа integer.
Что, однако, не помешает программу его туда засунуть. С плачевным результатом, само собой.
Это уже проблема вызывающего кода. Функция AddElement() принимает Integer, и всё.

-- Ср дек 12, 2012 18:19:14 --

shau-kote в сообщении #657794 писал(а):
venco в сообщении #657791 писал(а):
Вставлять в середину списка.

Хм. Ну, хорошо, согласен.
Хотя, учитывая, что первоначальная логика работы процедуры была "добавить элемент в конец списка", я бы предпочёл, чтобы она вернула ошибку.
Если уж так хочется именно в конец, то надо бы пробежать до этого конца, и вставить там.

-- Ср дек 12, 2012 18:25:57 --

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 02:45 
Аватара пользователя
venco в сообщении #657796 писал(а):
Это уже проблема вызывающего кода. Функция AddElement() принимает Integer, и всё.

Так, пардоньте, и то, что last не является указателем на последний элемент списка, проблема вызывающего кода, а не процедуры.
Процедура add(как и AddElement) принимает указатель на последний элемент и всё. (:

venco в сообщении #657796 писал(а):
Как вы уже поняли, если писать в первом стиле - типа библиотеку с возможностью повторного использования, то надо тщательнее подходить к разработке как интерфейса, так и имплементации. А скорее всего, такая библиотека уже есть, и лучше использовать уже готовое.
Если же код пишется на один раз, то проще, да и короче, писать во втором стиле, зная какие есть пре- и пост- условия на месте, и пользуясь этим.

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение13.12.2012, 02:59 
shau-kote в сообщении #657800 писал(а):
venco в сообщении #657796 писал(а):
Это уже проблема вызывающего кода. Функция AddElement() принимает Integer, и всё.

Так, пардоньте, и то, что last не является указателем на последний элемент списка, проблема вызывающего кода, а не процедуры.
Процедура add(как и AddElement) принимает указатель на последний элемент и всё. (:
Какой именно элемент - не ясно, т.к. тип тот же. А вот не-Integer передать в AddElement() невозможно, что именно вы собираетесь проверять?

shau-kote в сообщении #657800 писал(а):
Повышение гибкости программы? Удобство дальнейшей модификации?
Это уже будет не одноразовый код. Разделение не по размеру, а по повторному использованию. Вы гораздо больше времени потеряете на раздумья, а такие ли аргументы я дал, а что будет, если параметры не те. В одноразовом коде они не могут быть не те.

 
 
 [ Сообщений: 82 ]  На страницу 1, 2, 3, 4, 5, 6  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group