AVK Selected

Показавшиеся интересными, на мой вкус, посты

[Этюд, C#] Ненужный null

nikov nikov
Это загадка, которую я недавно публиковал на Twitter и давал коллегам на работе. Пока что её отгадал только один человек — Mads Torgersen (причём почти сразу).

Напишите валидную C# программу, которая содержит следующую последовательность токенов:
? null :

и которая остаётся валидной, если мы уберём токен null из этой последовательности, т.е. оставим
?      :


  Пояснения
* Валидная программа — это программа, которая компилируется без ошибок. Она может быть как приложением (.exe), так и библиотекой классов (.dll).
* Комментарии, части строковых литералов, имена регионов, текст в пропущенных секциях (#if false) и т.д. не являются токенами.
* Части токенов не являются токенами (например, символ `:` в выражении `foo::bar` или `?` в выражении `foo ?? bar` не являются токенами)
* Runtime поведение программы несущественно. То, что оно может измениться при удалении токена null, также несущественно.
ilih
ilih
23.12.2013 08:17
Здравствуйте, nikov, Вы писали:

N>Это загадка, которую я недавно публиковал на Twitter и давал коллегам на работе. Пока что её отгадал только один человек — Mads Torgersen (причём почти сразу).


N>Напишите валидную C# программу, которая содержит следующую последовательность токенов:
N>? null :
N>

N>и которая остаётся валидной, если мы уберём токен null из этой последовательности, т.е. оставим
N>?      :
N>


N>
  Пояснения
N>* Валидная программа — это программа, которая компилируется без ошибок. Она может быть как приложением (.exe), так и библиотекой классов (.dll).
N>* Комментарии, части строковых литералов, имена регионов, текст в пропущенных секциях (#if false) и т.д. не являются токенами.
N>* Части токенов не являются токенами (например, символ `:` в выражении `foo::bar` или `?` в выражении `foo ?? bar` не являются токенами)
N>* Runtime поведение программы несущественно. То, что оно может измениться при удалении токена null, также несущественно.


так? или я условия неправильно понял?
class A
{
   void M1()
   {
      var a = true ? M2(null) : 0;
      var b = true ? M2() : 0;
   }

   int M2()
   {
      return 0;
   }

   int M2(Object o)
   {
      return 0;
   }
}
nikov
nikov
23.12.2013 08:26
Здравствуйте, ilih, Вы писали:

I>так? или я условия неправильно понял?

I>
I>      var a = true ? M2(null) : 0;
I>


В исходной программе должны быть три токена
? null :

следующих один за другим. Между ними не должны присутствовать какие-либо другие токены.
scale_tone
scale_tone
24.12.2013 06:28
Здравствуйте, nikov, Вы писали:

N>Напишите валидную C# программу, которая содержит следующую последовательность токенов:
N>? null :
N>

N>и которая остаётся валидной, если мы уберём токен null из этой последовательности, т.е. оставим
N>?      :
N>


Добавлять/удалять другие слова вне этой последовательности токенов можно?
nikov
nikov
24.12.2013 08:56
Здравствуйте, scale_tone, Вы писали:

_>Добавлять/удалять другие слова вне этой последовательности токенов можно?


Нет.
Sinclair
Sinclair
24.12.2013 06:56
Здравствуйте, nikov, Вы писали:

N>Это загадка, которую я недавно публиковал на Twitter и давал коллегам на работе. Пока что её отгадал только один человек — Mads Torgersen (причём почти сразу).


N>Напишите валидную C# программу, которая содержит следующую последовательность токенов:
N>? null :
N>

N>и которая остаётся валидной, если мы уберём токен null из этой последовательности, т.е. оставим
N>?      :
N>

Пока что у меня проблема даже с тем, чтобы хотя бы написать валидную программу с последовательностью токенов ? :.
Прошерстил спеку C# 5.0. Colon можно использовать в:
1. Тернарном операторе: не подходит, между ? и : должен быть expression
2. Указателе базового класса: не подходит, слева от : будет либо идентификатор, либо идентификатор <параметры>
3. Label: не подходит, слева от : должен быть идентификатор
4. Case label: не подходит, слева от : должно быть constant expression
5. Декларации атрибута: не подходит, слева от : будет одно из предопределённых ключевых слов
6. Указании именованного параметра в вызове функции: не подходит, слева от : должен быть идентификатор
7. Указании constraint на параметр типа: не подходит, слева от : должен быть идентификатор
8. Декларации конструктора, для обращения к base(...) или this(...): не подходит, слева от : будет )
9. Декларации enum для указания интегрального базового типа: не походит, слева от : должен быть идентификатор
10. В doc comments, но их мы вроде бы не рассматриваем.
Вроде всё.
scale_tone
scale_tone
24.12.2013 07:45
Здравствуйте, Sinclair, Вы писали:

S>Пока что у меня проблема даже с тем, чтобы хотя бы написать валидную программу с последовательностью токенов ? :.


Это-то не проблема:

static object o;

static bool? Test1()
{
    return o is bool 
        ? null : 
    (bool?)false;
}

static bool? Test2()
{
    return true ? o is bool 
        ? : 
    false;
}


А вот как обойтись _только_ удалением null —
Sinclair
Sinclair
24.12.2013 08:45
Здравствуйте, scale_tone, Вы писали:

_>А вот как обойтись _только_ удалением null —

Так вы же уже написали ответ:

static bool? Test2()
{
    return true ? o is bool 
        ? : 
    (bool?)false;
}

Ведь bool к bool? приводится автоматически.
scale_tone
scale_tone
24.12.2013 09:37
Здравствуйте, Sinclair, Вы писали:

S>Так вы же уже написали ответ:


nikov, это ответ?

object o = null;

Func<bool?> f1 = () => 
    o is bool
        ? null :
    (bool?)false;

Func<bool?> f2 = () =>
    true ? o is bool
        ?  :
    (bool?)false;
nikov
nikov
24.12.2013 09:01
Здравствуйте, scale_tone, Вы писали:

_>nikov, это ответ?


_>
_>object o = null;

_>Func<bool?> f1 = () => 
_>    o is bool
_>        ? null :
_>    (bool?)false;

_>Func<bool?> f2 = () =>
_>    true ? o is bool
_>        ?  :
_>    (bool?)false;
_>


Конечно, нет. Это даже не валидная программа на C#.
gravatar
Аноним
24.12.2013 09:24
Здравствуйте, scale_tone, Вы писали:


_>static bool? Test2()

_>{
_> return true ? o is bool
_> ? :
_> false;
_>}
_>[/c#]

а как это воспринимает компилятор? почему компилит?
QrystaL
QrystaL
24.12.2013 09:32
Здравствуйте, Аноним, Вы писали:
А>а как это воспринимает компилятор? почему компилит?

static bool? Test2()
{
    return true
        ? o is bool?
        : false;
}
Doc
Doc
24.12.2013 09:37
Здравствуйте, Аноним, Вы писали:

А>почему компилит?


Потому что код валидный, но из-за форматирования тут обман зрения. (там bool?
notacat
notacat
24.12.2013 08:33
S>Пока что у меня проблема даже с тем, чтобы хотя бы написать валидную программу с последовательностью токенов ? :.
S>Прошерстил спеку C# 5.0. Colon можно использовать в:

если про 6, то там, говорят, еще такое будет:

//monadic null checking —
if (points?.FirstOrDefault()?.X ?? -1) { }


т.е. в этом случае вопрос может относиться к проверке на null. Тогда something? может быть первым выражением перед двоеточием в тернарном операторе.
AndrewVK
AndrewVK
25.12.2013 09:09
Здравствуйте, notacat, Вы писали:

N>если про 6, то там, говорят, еще такое будет:


N>

N>//monadic null checking —
N>if (points?.FirstOrDefault()?.X ?? -1) { }


Это пока что далеко не финальный синтаксис и может еще 100 раз поменяться.
... << RSDN@Home 1.2.0 alpha 5 rev. 100 on Windows 8 6.2.9200.0>>
SergeyT.
SergeyT.
24.12.2013 09:53
Здравствуйте, nikov, Вы писали:

var x = 42;
var a = (x is int?) ? x is int ? null : (bool?)true : (bool?)true;
var b = (x is int?) ? x is int ? : (bool?)true;


Это не совсем честно, поскольку изменение заключается не только в удалении токена null, но и еще одного выражения
nikov
nikov
24.12.2013 08:59
Здравствуйте, SergeyT., Вы писали:

ST>Это не совсем честно, поскольку изменение заключается не только в удалении токена null, но и еще одного выражения


Кроме удаления null ничего больше менять нельзя.
IT
IT
24.12.2013 09:32
Здравствуйте, nikov, Вы писали:

Развлекаетесь?

Какие ещё есть конструкции, заканчивающиеся на '?' кроме предиката is? Очевидно лямбда, заканчивающаяся предикатом is.
scale_tone
scale_tone
26.12.2013 08:27
Здравствуйте, nikov, Вы писали:

N>Напишите валидную C# программу, которая содержит следующую последовательность токенов:
N>? null :
N>

N>и которая остаётся валидной, если мы уберём токен null из этой последовательности, т.е. оставим
N>?      :
N>


Ну, почти...
public struct Dummy : IDisposable
{
    public void Dispose()
    {
    }

    public static implicit operator bool(Dummy d)
    {
        return true;
    }

    public static implicit operator Dummy(bool b)
    {
        return true;
    } 
}

class Program
{
    static bool Dummy = true;

    static void Main()
    {
        object o = null;
        Dummy? d = new Dummy();

        using
        (
            Dummy ? 
                Dummy = o is Dummy
                    ? null :
                d
        ){}

        using
        (
            (bool)
            Dummy ? 
                Dummy = o is Dummy
                    ?     :
                d
        ){}
    }
}


Осталось понять, почему без выделенного перестает компилиться. Кто поможет?
scale_tone
scale_tone
26.12.2013 08:32
Здравствуйте, scale_tone, Вы писали:

_>Осталось понять, почему без выделенного перестает компилиться. Кто поможет?


Стоп! Оно же скомпилировалось!! Voila!!!


public struct Dummy : IDisposable
{
    public void Dispose()
    {
    }

    public static implicit operator bool(Dummy d)
    {
        return true;
    }

    public static implicit operator Dummy(bool b)
    {
        return true;
    } 
}

class Program
{
    static bool Dummy = true;

    static void Main()
    {
        object o = null;
        Dummy? d = new Dummy();

        using
        (
            Dummy ? 
                Dummy = o is Dummy
                    ? null :
                d
        ){}

        using
        (
            Dummy ? 
                Dummy = o is Dummy
                    ?     :
                d
        ){}
    }
}



nikov
nikov
26.12.2013 08:35
Здравствуйте, scale_tone, Вы писали:

_>Стоп! Оно же скомпилировалось!! Voila!!!


_>
_>        using
_>        (
_>            Dummy ? 
_>                Dummy = o is Dummy
_>                    ? null :
_>                d
_>        ){}
_>



Точно!
scale_tone
scale_tone
27.12.2013 08:55
Здравствуйте, nikov, Вы писали:

N>Точно!


М-да. Решарпер при подобных экспериментах, конечно, стоит отключать...

И еще интересно, зачем компилятор позволяет делать такое:
struct S : IDisposable
{
    public void Dispose(){}
}

static void Main()
{
    using(S? s = null){}
}


nikov
nikov
14.01.2014 03:37
Здравствуйте, scale_tone, Вы писали:

_>И еще интересно, зачем компилятор позволяет делать такое:

_>
_>    using(S? s = null){}
_>


Видимо, потому что вместо null может быть более сложный инициализатор (вызов метода, например), который может вернуть как null, так и значение, которое в конце нужно будет освободить с помощью Dispose. Точно так же, как и с ссылочными типами.
scale_tone
scale_tone
14.01.2014 08:10
Здравствуйте, nikov, Вы писали:

N>Видимо, потому что вместо null может быть более сложный инициализатор (вызов метода, например), который может вернуть как null, так и значение, которое в конце нужно будет освободить с помощью Dispose. Точно так же, как и с ссылочными типами.


И правда. Оказывается, можно написать как-то так:
void DoWithUnitOfWork(Action task1, Action task2, IDisposable unitOfWorkImpl = null)
{
    using (unitOfWorkImpl)
    {
        task1(); task2();
    }
}


и оно не упадет.