Здравствуйте, Cyberax, Вы писали:
C>И что? Чем этому мешает break и goto? Прекрасно можно доказывать C>кооректность программ и с ними.
Можно, но без "прекрасно".
Я даже не хочу повторять за Edsger W. Dijkstra почему так.
>> Что касается выхода из циклов по флагам и отсутствия break, то вообще >> не понимаю в чем проблема — что мешает вынести цикл в отдельную >> функцию и выходить исключительно из цикла, делая код более предсказуемым?
C>Слишком много переменных может потребоваться передавать в виде параметров.
Ну наверное может. А может и нет. Или наоборот. О чем вообще мы?
C>Нет уж, сами затеяли спор — сами и показывайте код, который C>множественный выход делает недоказуемым и вообще отстойным.
Извините, это вы говорите, что у вас есть такой код. Что он есть у меня, я не говорил.
А я такого кода не пишу.
Будем продолжать беседы о том сколько ангелов уместится на острие иголки?
Все asserts идут лесом. Но дело даже не в этом. Ты собираешься на любую возможную ситуацию в программе писать assert? Этак у тебя на 10 строчек кода должно быть 20 asserts.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, reductor, Вы писали:
R>Компиляторы конечно пусть выполняют свою работу, но есть все же некоторое соответствие между количеством их работы и нашим пониманием того, что мы делаем.
Ага, компиляторы оставлены в покое, это уже прогресс
R>А так же между количеством их работы и умственным напряжением того человека, который будет читать наш код.
Не хочешь переписать вот такой код без returns?
private static MemberMapper GetNullableMemberMapper(MapMemberInfo mi)
{
Type type = mi.MemberAccessor.Type;
if (type.IsGenericType == false || mi.MapValues != null)
return null;
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType == null)
return null;
if (underlyingType.IsEnum)
{
underlyingType = Enum.GetUnderlyingType(underlyingType);
if (underlyingType == typeof(SByte)) return new NullableSByteMapper. Enum();
if (underlyingType == typeof(Int16)) return new NullableInt16Mapper. Enum();
if (underlyingType == typeof(Int32)) return new NullableInt32Mapper. Enum();
if (underlyingType == typeof(Int64)) return new NullableInt64Mapper. Enum();
if (underlyingType == typeof(Byte)) return new NullableByteMapper. Enum();
if (underlyingType == typeof(UInt16)) return new NullableUInt16Mapper.Enum();
if (underlyingType == typeof(UInt32)) return new NullableUInt32Mapper.Enum();
if (underlyingType == typeof(UInt64)) return new NullableUInt64Mapper.Enum();
}
else
{
if (underlyingType == typeof(SByte)) return new NullableSByteMapper();
if (underlyingType == typeof(Int16)) return new NullableInt16Mapper();
if (underlyingType == typeof(Int32)) return new NullableInt32Mapper();
if (underlyingType == typeof(Int64)) return new NullableInt64Mapper();
if (underlyingType == typeof(Byte)) return new NullableByteMapper();
if (underlyingType == typeof(UInt16)) return new NullableUInt16Mapper();
if (underlyingType == typeof(UInt32)) return new NullableUInt32Mapper();
if (underlyingType == typeof(UInt64)) return new NullableUInt64Mapper();
if (underlyingType == typeof(Char)) return new NullableCharMapper();
if (underlyingType == typeof(Single)) return new NullableSingleMapper();
if (underlyingType == typeof(Boolean)) return new NullableBooleanMapper();
if (underlyingType == typeof(Double)) return new NullableDoubleMapper();
if (underlyingType == typeof(DateTime)) return new NullableDateTimeMapper();
if (underlyingType == typeof(Decimal)) return new NullableDecimalMapper();
if (underlyingType == typeof(Guid)) return new NullableGuidMapper();
}
return null;
}
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Ракот, Вы писали:
IT>>Избавиться от лишних локальных переменных — задача оптимизатора.
Р>Все, конечно, верно. Только в коде это не уберешь — теряется чистота.
Что-то я начал терять ход мыслей О каких локальных переменных идёт речь?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Mamut, Вы писали:
M>Яркий пример — разбор ХМЛя многими библиотеками. Обычно достаточно знать, что ХМЛ невалидный и сразу завершить работу:
M>Например, кусок:
Здравствуйте, Сергей Губанов, Вы писали:
СГ>1) Вот, не надуманный пример. СГ>2) Следующий ненадуманный пример.
Не надо обобщать косяки в реализации конкретных методов криворукими девелоперами на весь механизм исключений. Этак я могу специально для тебя написать какого-нибудь уродца на Обероне, тем самым дав твоим аппонентам в руки очень "весомые" аргументы поносить его налево и направо.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
reductor wrote:
> C>И что? Чем этому мешает break и goto? Прекрасно можно доказывать > C>кооректность программ и с ними. > Можно, но без "прекрасно".
Замечательно. Теперь рассказать как можно преобразовать AST с multiple
returns в AST с single returns?
> C>Слишком много переменных может потребоваться передавать в виде > параметров. > Ну наверное может. А может и нет. Или наоборот. О чем вообще мы?
Не знаю. Кто-то пытается мне зубы заговорить, кажется.
> C>Нет уж, сами затеяли спор — сами и показывайте код, который > C>множественный выход делает недоказуемым и вообще отстойным. > Извините, это вы говорите, что у вас есть такой код. Что он есть у > меня, я не говорил. > А я такого кода не пишу.
Здравствуйте, Cyberax, Вы писали:
C>Нет, это уже религия. Все нормальные программисты уже давно перестали C>флеймить по поводу GOTO и структурного программирования, так как по C>нынешним меркам это уже далеко не самый главный вопрос. Все C>программисты, которых я знаю, думают примерно так: "GOTO это плохо?" — C>"Плохо". "Структурное программирование хорошо?" — "Да". "Единый return, C>выход из вложенных циклов по флагам, отсутствие break — оно надо?" — "А C>нафига?"
Честно говоря кроме структурного программирования есть еще куча стилей где goto не является противоречием. Например — автоматное программирование, на чем он и построен. Или например лисповские continuation.
Что касается множественного выхода, то противоречий я здесь не вижу. В отличие от goto его всегда можно трансформировать в классическую структурную схему.
Здравствуйте, IT, Вы писали:
IT>Все asserts идут лесом. Но дело даже не в этом. Ты собираешься на любую возможную ситуацию в программе писать assert? Этак у тебя на 10 строчек кода должно быть 20 asserts.
В некоторых особо жарких местах у меня бывало и такое. И иногда даже помогало.
Здравствуйте, IT, Вы писали:
IT>На плюсах и я таким частенько грешил На шарпе пока как-то надобности не было.
При отладке windows сервисов вставлял в код даже не assert, а прямой вызов дебаггера.
Здравствуйте, GlebZ, Вы писали:
IT>>На плюсах и я таким частенько грешил На шарпе пока как-то надобности не было. GZ>При отладке windows сервисов вставлял в код даже не assert, а прямой вызов дебаггера.
Это другой случай. При разработке UI иногда даже два монитора не помогают, если надо с фокусом повозиться, который постоянно уходит в отладчик. Приходится по старинке выводить всё что нужно в лог. Но это всё 5-10% случаев.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Ну, значит, вот так:
А теперь добавь сюда какую-нибудь вменяемую информацию об ошибке, сделай так чтобы TransferMoney возвращала новый баланс счёта и протащи это через 4-5 вызовов.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, reductor, Вы писали:
R>>Компиляторы конечно пусть выполняют свою работу, но есть все же некоторое соответствие между количеством их работы и нашим пониманием того, что мы делаем.
IT>Ага, компиляторы оставлены в покое, это уже прогресс
R>>А так же между количеством их работы и умственным напряжением того человека, который будет читать наш код.
IT>Не хочешь переписать вот такой код без returns?
Ок. Только сразу предупреждаю, я вообще не знаю C# (как и .NET), потому пришлось msdn почитать.
Могут быть ошибки (как в оптимальности реализации, так и в понимании логики того, что здесь происходит), но в общем вроде все так.
private static MemberMapper MapperFromTC (TypeCode tc) {
MemberMapper value;
switch (tc) {
case TypeCode.SByte: value = new NullableSByteMapper(); break;
case TypeCode.Int16: value = new NullableInt16Mapper(); break;
case TypeCode.Int32: value = new NullableInt32Mapper(); break;
case TypeCode.Int64: value = new NullableInt64Mapper(); break;
case TypeCode.Byte: value = new NullableByteMapper(); break;
case TypeCode.UInt16: value = new NullableUInt16Mapper(); break;
case TypeCode.UInt32: value = new NullableUInt32Mapper(); break;
case TypeCode.UInt64: value = new NullableUInt64Mapper(); break;
case TypeCode.Char: value = new NullableCharMapper(); break;
case TypeCode.Single: value = new NullableSingleMapper(); break;
case TypeCode.Boolean: value = new NullableBooleanMapper(); break;
case TypeCode.Double: value = new NullableDoubleMapper(); break;
case TypeCode.DateTime: value = new NullableDateTimeMapper(); break;
case TypeCode.Decimal: value = new NullableDecimalMapper(); break;
case TypeCode.Guid: value = new NullableGuidMapper(); break;
default: value = null; break;
}
return value;
}
private static MemberMapper GetNullableMemberMapper(MapMemberInfo mi) {
Type type = mi.MemberAccessor.Type;
MemberMapper value;
if (type.IsGenericType == true && mi.MapValues == null) {
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null) {
value = MapperFromTC(underlyingType.IsEnum
? underlyingType.GetTypeCode()
: Type.GetTypeCode(underlyingType));
} else {
value = null;
}
} else {
value = null;
}
return value;
}
Если интересен был proof-of-concept, то вот. Ничего, что я добавил "лишнюю" функцию? а то читать было сложновато.
В общем-то в case-ах и if'ах можно было и return'ы оставить (вариантов без них не остается), но чтобы лишнего флейма избежать, я сделал с переменной.
Хотя идеально бы конечно было, если бы switch возвращал значение. Но так зато можно дополнительно в выводить в лог mm перед каждым возвратом. и то хлеб. Надеюсь, больше на C# ничего делать не придется.
Здравствуйте, reductor, Вы писали:
R>Ок. Только сразу предупреждаю, я вообще не знаю C# (как и .NET), потому пришлось msdn почитать.
Совсем не плохо для начала, хотя я просил повторить в точности то что есть, а не самовольничать
R>Могут быть ошибки (как в оптимальности реализации, так и в понимании логики того, что здесь происходит), но в общем вроде все так.
Тут две проблемы.
1. Для типа Guid не существует TypeCode.
2. Для перечислений создаются другие мапперы, т.е. нужна будет ещё одна функция.
Но даже и в таком виде очень хорошо видно, что наглядность кода не возрасла. К тому же можно было бы предложить вариант для SqlTypes: SqlInt16, SqlInt32 и т.п. для которых нет TypeCodes.
R>Если интересен был proof-of-concept, то вот. Ничего, что я добавил "лишнюю" функцию? а то читать было сложновато.
То-то и оно.
R>Надеюсь, больше на C# ничего делать не придется.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Cyberax, Вы писали:
C>reductor wrote:
>> C>И что? Чем этому мешает break и goto? Прекрасно можно доказывать >> C>кооректность программ и с ними. >> Можно, но без "прекрасно".
C>Замечательно. Теперь рассказать как можно преобразовать AST с multiple C>returns в AST с single returns?
при чем здесь AST?
по вашему, исходя из этого:
if (cond) return 1
return 0
можно утверждать, что имелось в виду это:
if (cond) return 1
else return 0
?
а под этим:
if (cond1)
if (cond2) return 2
return 0
подразумевалось без сомнения это:
if (cond1)
if (cond2) return 2
else return 0
else return 0
?
Или я говорил, что код с несколькими стейтментами return не может работать корректно?
или что его нельзя в AST трансформировать во что-то там? Или что его нельзя скомпилировать?
Я утверждал, что без явной обработки всех условий вероятность ошибки и последующая с этим возня могут возрасти многократно.
Без нее где-нибудь код будет ждать вариант, который функция никогда не возвращает, потому что кто-то написал красивый трансформер для AST, который тем не менее вряд ли умеет еще и проверять возвращает ли функция все возможные значения или только половину из них.
>> C>Слишком много переменных может потребоваться передавать в виде >> параметров. >> Ну наверное может. А может и нет. Или наоборот. О чем вообще мы?
C>Не знаю. Кто-то пытается мне зубы заговорить, кажется.
По-моему кто-то не держит себя в руках. Код со многими переменными можно глянуть?.
>> C>Нет уж, сами затеяли спор — сами и показывайте код, который >> C>множественный выход делает недоказуемым и вообще отстойным. >> Извините, это вы говорите, что у вас есть такой код. Что он есть у >> меня, я не говорил. >> А я такого кода не пишу.
C>И судите о сложности чтения multiple returns?
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, reductor, Вы писали:
R>>Ок. Только сразу предупреждаю, я вообще не знаю C# (как и .NET), потому пришлось msdn почитать.
IT>Совсем не плохо для начала, хотя я просил повторить в точности то что есть, а не самовольничать
R>>Могут быть ошибки (как в оптимальности реализации, так и в понимании логики того, что здесь происходит), но в общем вроде все так.
IT>Тут две проблемы. IT>1. Для типа Guid не существует TypeCode.
ну можно в default там добавить проверку на Guid дополнительно, вроде
IT>2. Для перечислений создаются другие мапперы, т.е. нужна будет ещё одна функция.
А.. точно, я не заметил вызовы .Enum()
Можно передавать вторым параметром флаг и перед возвратом, если true и != null, то вернуть value.Enum()
Или что-нибудь такое. Наверняка есть миллион способов не дублировать кучу кода
IT>Но даже и в таком виде очень хорошо видно, что наглядность кода не возрасла. К тому же можно было бы предложить вариант для SqlTypes: SqlInt16, SqlInt32 и т.п. для которых нет TypeCodes.