Перечитав все, чем я был недоволен С# тут я выяснил, что кроме отсутствия SortedSet, который был объявлен только в .NET 4.0, C# тут абсолютно perfect. CBR7 это подтвердил.
Характерно, что после всего четырех месяцев работы на C# я уже чуствую неудобство работы на других языках. Как однажды сказал один крутой (для меня :о)) ACM-щик, "я пишу не на С++, я пишу на STL". Вот также и тут, я пишу не на C#, я пишу на Linq :о) Потому что без Linq С# это таже самая Java, только без BigInteger (BigInteger появился тоже только в .NET 4.0). И поэтому я должен сказать спасибо Михаилу, так как реально сегодня нормальной версии C# с Linq почти нигде на регулярных соревнованиях нет (и на TC и у снарка C# cтарый, без Linq).
Теперь немного рекламы. Почему же я тащусь от C#.
1. Мне не надо писать тип объекта, который я создаю. На С++ это не проблема, но на Java в принципе она проявляется, хотя, конечно, Java программисты на нее не обращают внимания. Допустим,
List<int> q = new List<int>( );
Тупо - я пишу тип дважды. Конечно, это плохой пример - любая интегрированная среда сразу после набора слова new предложит по Enter или типа того тим переменной, и реально человек наберет List<int> только однажны. Но что, если мне надо
(тип переменной) q = SomeClass.SomeMethod( ).SomeOtherMethod( )...
Я не хочу задумываться, какого типа будет возвращаемое значение этого SomeOtherMethod, я могу вообще теоретически не знать до набора этой строки, какой будет тип. В C# на этот случай есть ключевое слово var.
var lst = new List<int>( );
var q = SomeClass.SomeMethod( ).SomeOtherMethod( )...
Всегда, когда компилятор может сам понять тип переменной (то есть грубо говоря всегда, когда вы ее сразу инициализируете), ее тип можно не указывать лапками.
2. Мне не надо создавать типы данных под все подряд
Я хочу создать переменную, с тремя полями: id, x и y. Когда параметров два, C++ шники всегда юзают pair - это круто, в Java даже для двух надо делать отдельный тип. В любом случае, если полей три, то на C++ тоже надо создавать новый тип. На C# все проще
var q = new { id = 4, x = 4, name = 5 };
И все, мне не надо проматывать код чтобы создать новый класс. Но вы не прочуствуете всей мощи этого, пока не прочитаете пункт 3.
3. А теперь, когда у меня есть непонятные типы, я хочу их сортировать. Я не хочу переопределять операторы, мне лень это делать :о Приходит на помощь Linq. Допустим, что qs - это массив чего-то типа q, который я создал на прошлом шагу
var qs_sorted = ( from q in qs orderby q.id select q );
И все. Никаких переопределений операторов :о)
Я хочу отфильтровать его, оставив только те, где x < 10?
var qs_filtered = ( from q in qs where q.x < 10 orderby q.id select q );
Я хочу при этом получить только x и y, и откинуть id?
var qs_xy = ( from q in qs where q.x < 10 orderby q.id let x = q.x let y = q.y select new { x, y } );
4. Это уже не про язык или платформу, а про среду. Почему многие любят C++? Потому что там можно записать макросы для циклов. На топкодере почти у всех есть макрос для фора. Потому что в 90% случаев фор делается по проторенной дорожке for( i = 0; i < n; ++ i ) или for( i = n - 1; i >= 0; -- i ). Меняется только i и n. Разумеется, у всех набита рука вбивать это дело, но хочется все-таки вбивать только i и n. Поэтому макросы типа FOR(i,n) или rep(i,n) или типа того очень популярны. В Visual Studio мы делаем так. Пишем for, дважды бьем кнопку Tab, нам сразу разворачивается вся конструкция и курсор установлен на то место, где мы хотим вбить название переменной. И название сразу i. Меняем название на j, все три вхождения i меняются на j. Жмем tab, попадаем на length, меняем length на то, что нам надо, скажем n, жмем Enter и попадаем в тело цикла. Надо цикл с конца - делаем все тоже самое, написав в начале forr вместо for. Эта фишка называется Code Snippets, и она реально крутая. Не удивлюсь, если в других средах разработки она тоже есть.
5. Добавим к этому перегрузку операторов, которая все-таки есть, параметры по умолчанию для методов, причем более мощные, чем в C++ - грубо говоря вы не обязаны предоставлять параметры для функции по порядку, вы можете сделать 100 параметров, все с значениями по умолчанию, а потом вызвать эту функцию, передав только 18-ый и 99-ый. В С++ вы обязаны передавать параметры начиная с начала и поюзать значения по умолчанию только для подрядидущих с конца параметров.
Но видимо это все уже олимпиаднику не надо :о)
С учетом SortedSet и BigInteger в .NET4.0 C# в принципе будет иметь все, что надо в стандартной библиотеке. Сегодня приходится использовать SortedDictionary вместо SortedSet, что немного тупо :о( И для длинной арифметики приходится писать на Java не редко.
Кстати, в .NET 4.0 для BigInteger перегружены все опреаторы, и с ним можно тискаться как с любыми другими типами :о) Это вам не громоздкие конструкции на Java писать с тонной вызовов методов :о
Характерно, что после всего четырех месяцев работы на C# я уже чуствую неудобство работы на других языках. Как однажды сказал один крутой (для меня :о)) ACM-щик, "я пишу не на С++, я пишу на STL". Вот также и тут, я пишу не на C#, я пишу на Linq :о) Потому что без Linq С# это таже самая Java, только без BigInteger (BigInteger появился тоже только в .NET 4.0). И поэтому я должен сказать спасибо Михаилу, так как реально сегодня нормальной версии C# с Linq почти нигде на регулярных соревнованиях нет (и на TC и у снарка C# cтарый, без Linq).
Теперь немного рекламы. Почему же я тащусь от C#.
1. Мне не надо писать тип объекта, который я создаю. На С++ это не проблема, но на Java в принципе она проявляется, хотя, конечно, Java программисты на нее не обращают внимания. Допустим,
List<int> q = new List<int>( );
Тупо - я пишу тип дважды. Конечно, это плохой пример - любая интегрированная среда сразу после набора слова new предложит по Enter или типа того тим переменной, и реально человек наберет List<int> только однажны. Но что, если мне надо
(тип переменной) q = SomeClass.SomeMethod( ).SomeOtherMethod( )...
Я не хочу задумываться, какого типа будет возвращаемое значение этого SomeOtherMethod, я могу вообще теоретически не знать до набора этой строки, какой будет тип. В C# на этот случай есть ключевое слово var.
var lst = new List<int>( );
var q = SomeClass.SomeMethod( ).SomeOtherMethod( )...
Всегда, когда компилятор может сам понять тип переменной (то есть грубо говоря всегда, когда вы ее сразу инициализируете), ее тип можно не указывать лапками.
2. Мне не надо создавать типы данных под все подряд
Я хочу создать переменную, с тремя полями: id, x и y. Когда параметров два, C++ шники всегда юзают pair - это круто, в Java даже для двух надо делать отдельный тип. В любом случае, если полей три, то на C++ тоже надо создавать новый тип. На C# все проще
var q = new { id = 4, x = 4, name = 5 };
И все, мне не надо проматывать код чтобы создать новый класс. Но вы не прочуствуете всей мощи этого, пока не прочитаете пункт 3.
3. А теперь, когда у меня есть непонятные типы, я хочу их сортировать. Я не хочу переопределять операторы, мне лень это делать :о Приходит на помощь Linq. Допустим, что qs - это массив чего-то типа q, который я создал на прошлом шагу
var qs_sorted = ( from q in qs orderby q.id select q );
И все. Никаких переопределений операторов :о)
Я хочу отфильтровать его, оставив только те, где x < 10?
var qs_filtered = ( from q in qs where q.x < 10 orderby q.id select q );
Я хочу при этом получить только x и y, и откинуть id?
var qs_xy = ( from q in qs where q.x < 10 orderby q.id let x = q.x let y = q.y select new { x, y } );
4. Это уже не про язык или платформу, а про среду. Почему многие любят C++? Потому что там можно записать макросы для циклов. На топкодере почти у всех есть макрос для фора. Потому что в 90% случаев фор делается по проторенной дорожке for( i = 0; i < n; ++ i ) или for( i = n - 1; i >= 0; -- i ). Меняется только i и n. Разумеется, у всех набита рука вбивать это дело, но хочется все-таки вбивать только i и n. Поэтому макросы типа FOR(i,n) или rep(i,n) или типа того очень популярны. В Visual Studio мы делаем так. Пишем for, дважды бьем кнопку Tab, нам сразу разворачивается вся конструкция и курсор установлен на то место, где мы хотим вбить название переменной. И название сразу i. Меняем название на j, все три вхождения i меняются на j. Жмем tab, попадаем на length, меняем length на то, что нам надо, скажем n, жмем Enter и попадаем в тело цикла. Надо цикл с конца - делаем все тоже самое, написав в начале forr вместо for. Эта фишка называется Code Snippets, и она реально крутая. Не удивлюсь, если в других средах разработки она тоже есть.
5. Добавим к этому перегрузку операторов, которая все-таки есть, параметры по умолчанию для методов, причем более мощные, чем в C++ - грубо говоря вы не обязаны предоставлять параметры для функции по порядку, вы можете сделать 100 параметров, все с значениями по умолчанию, а потом вызвать эту функцию, передав только 18-ый и 99-ый. В С++ вы обязаны передавать параметры начиная с начала и поюзать значения по умолчанию только для подрядидущих с конца параметров.
Но видимо это все уже олимпиаднику не надо :о)
С учетом SortedSet и BigInteger в .NET4.0 C# в принципе будет иметь все, что надо в стандартной библиотеке. Сегодня приходится использовать SortedDictionary вместо SortedSet, что немного тупо :о( И для длинной арифметики приходится писать на Java не редко.
Кстати, в .NET 4.0 для BigInteger перегружены все опреаторы, и с ним можно тискаться как с любыми другими типами :о) Это вам не громоздкие конструкции на Java писать с тонной вызовов методов :о
ACM ICPC вообще отвратительно организованное соревнование.
Про организацию - это я просто не касаемо C# сказал. IBM обнищал, и последний ЧМ был просто отвратительный. Вот если бы вы были на ЧМ в 2008 году, когда все проходило в нереально живописном месте, и, что очень важно, все проходило в одном месте, и если вы устали от идиотизма на открытии, когда куча нафиг никому не интересных официальных лиц заполняет полный граф поздравления друг друга, пучера и участников, то вы можете пойти в свой номер - потому что все в отеле.
И сравнить это все с финалом 2010, когда все проходило на помойке, открытие и все остальное было в 40 минутах езды на автобусе от отеля, без интернета, поэтому когда через 10 минут после начала открытия вы поняли, что ДОМ-2 - это не самое долбануца нудное шоу, но деваться вам некуда - вот тут вы прозреваете с организации :о)
А еще кстати постоянный эффект ACM ICPC, кто был - тот знает. На закрытии, которое длится допустим час, в течение 40 минут поздравляют всех организаторов, IBM, UPE, волонтеров, их всех вызывают на сцену, называют по именам, всем в зале на это нахрен посрать.
А потом в последние 20 минут поздравляют команды. Их вызывают на одну минуту на сцену (а как иначе за 20 минут поздравить 12 команд?) и (!!!) их НЕ называют по именам. Это вообще писец.
А уж попросить команды "произнести" их ВУЗ при регистрации казалось бы вообще очевидное действие.
Кстати на TopCoder Open вообще всех называют по именам (или по крайней мере называли когда я там был), и ничего, справляются.
Параметры по умолчанию и именованные, к сожалению, лишь в C#4.0.
var qs_xy = ( from q in qs where q.x < 10 orderby q.id let x = q.x let y = q.y select new { x, y } );
стоит писать как:
var qs_xy = from q in qs
where q.x < 10
orderby q.id
let x = q.x let y = q.y
select new { x, y };
Это общепринятая практика и значительно повышает читабельность кода.
Это только малая часть LINQ - LINQ to Object.
Асимптотика не изменяется, та же, что и в Array.Sort. Какая? Нужно смотреть коды, коих у меня на машине нет. Должно быть O(n*log(n)).
Разве что JOIN для Linq to Object работает за квадрат, и это расстраивает...
Мне надо чтобы мой код влазил на экран, чтобы я в нем ориентировался. Я не хочу парсить вход в пять строк, допустим, мне нужен Linq как раз для того, чтобы сделать это в одну :о)
Позволю себе написать, как можно решить задачи из пункта 3 и кое-что другое на питоне (по-моему, сходство подходов очевидно).
---------------------------------------------------------------
q1 = (4, 4, 'mike')
q2 = (50, 50, 'petr')
q3 = (3, 3, 'alex')
qs = [q1, q2, q3] # create a list of tuples
print qs
def by_id (q):
id, x, name = q # unpacking a tuple - for clearity
return id
#return q[0] - the same
qs_sorted = sorted (qs, key = by_id)
print qs_sorted
# the same using lambda
qs_sorted = sorted (qs, key = lambda q: q[0])
print qs_sorted
qs_sorted_reversed = sorted (qs, key = lambda q: q[0], reverse = True)
print qs_sorted_reversed
qs_filtered = [q for q in qs if q[1] < 10]
print qs_filtered
qs_sorted_filtered = [q for q in sorted (qs, key = lambda q: q[0]) if q[1] < 10]
print qs_sorted_filtered
qs_xy = [(q[0], q[1]) for q in qs if q[1] < 10]
print qs_xy
qs_id_squared_x_cubed = [(q[0]**2, q[1]**3, q[2]) for q in qs]
print qs_id_squared_x_cubed
---------------------------------------------------------------
Надо тоже попробовать "just for fun" :о
Это уже не про язык или платформу, а про среду. Почему многие любят C++? Потому что там можно записать макросы для циклов. На топкодере почти у всех есть макрос для фора. Потому что в 90% случаев фор делается по проторенной дорожке for( i = 0; i < n; ++ i ) или for( i = n - 1; i >= 0; -- i ). Меняется только i и n. Разумеется, у всех набита рука вбивать это дело, но хочется все-таки вбивать только i и n. Поэтому макросы типа FOR(i,n) или rep(i,n) или типа того очень популярны. В Visual Studio, кодяча на C#, мы делаем так. Пишем for, дважды бьем кнопку Tab, нам сразу разворачивается вся конструкция и курсор установлен на то место, где мы хотим вбить название переменной. И название сразу i. Меняем название на j, все три вхождения i меняются на j. Жмем tab, попадаем на length, меняем length на то, что нам надо, скажем n, жмем Enter и попадаем в тело цикла. Надо цикл с конца - делаем все тоже самое, написав в начале forr вместо for. То есть мы нажали:
for \t \t j \t n \n
Не так плохо, не больше чем набирать rep( i, n )...
Эта фишка называется Code Snippets, и она реально крутая. Не удивлюсь, если в других средах разработки она тоже есть.
Поправьте, если ошибаюсь... Я так понимаю что Microsoft создаёт возможности для разработки ПО уровня предприятия на C#, но этим пока довольно мало кто пользуется в отличие от J2EE. С другой стороны настольных приложений на Java по-моему значительно меньше рожается.
Кстати, просветите, можно ли enterprise-разработку на Mono с успехом вести и если да, насколько это популярно?
Шарп действительно мощная штука, жаль, что не поддерживается много где. Вообще полноценный шарп - это шарп от microsoft, а значит дотнет, а значит windows, который стоит денег, так что на соревнованиях этого языка ждать не стоит.
По поводу linq - сначала использовал такой же синтаксис, потом перешел на extensions функции. Как-то строже смотрится. Кстати extensions тоже классная штука, правда в олимпиадном программировании, наверное, нет смысла ее применять.
Code snippets для олимпиадника просто открытие, я считаю. Минус дефайнов в том, что не все их любят и в команде кто-то использует, кто-то нет, а главное, нередко приходится менять тот же forn(i, n) на что-то вроде for(int i = 1; i <= n; ++i). Code snippets не скрывают код, а делают его автоматическую подстановку, которую можно настроить и изменить эту часть кода в дальнейшем.
А автоматическое определение типа с var и анонимные типы не требуют комментариев, удобство очевидно. Анонимные типы, кстати, это все еще строгая типизация, а значит IntelliSense никуда не девается.
Вообще, я давно пишу на C# и на C++, причем на плюсах только олимпиады, на шарпе - все остальное. И по какой-то причине, когда решал пару олимпиадных задач на C#, писать было сложнее чем на плюсах (ну кроме дат, конечно, очень удобные штуки DateTime и TimeSpan), видимо просто привычка.
Проблема даже не в том, что виндовс стоит денег. Не такие это большие деньги. Проблема именно в том что в то время как все потихоньку приходят к кроссплатформенной разработке на скриптовых языках, Java или QT, микрософт упорно пытается действовать наоборот - заставить весь мир использовать собственные решения. В принципе это не было бы так сложно, если бы решения микрософта были бесспорны и гениальны.
Я не говорю что различные линуксы бесспорны и гениальны - но по крайней мере чтобы развернуть ресурс сделанный на PHP, J2EE и т.п. человек может выбрать практически любой дистрибутив виндов или линуксов выпущенный за последние лет пять, либо взять подходящий сервер/хостинг. С ASP .NET ему нужен конкретный сервер с конкретной ОС. И не дай Бог проснуться утром и узнать что эта версия ОС снята с поддержки, и надо всем срочно перейти на Windows Ultra Ultimate Server.
Вот если б Микрософт активно поддержал проект Mono, я думаю это здорово помогло бы развитию в народе любви к C#.
Вообще-то для каждой версии винды заранее известна дата окончания поддержки. Причем намного заранее.
>С ASP .NET ему нужен конкретный сервер с конкретной ОС.
Не вижу никакой проблемы. Хостингов с ASP.NET полно и стоят они примерно также как и остальные.
Холивар детектед?
Мне кажется, Вы немного отошли от контекста. Лично мне тоже во многом не нравится стратегия microsoft, но я думаю, что там работают умные люди, и они знают, что делают. И, думаю, причина как раз в деньгах =)