Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 19

ImgChain

# pipeline stages
add compound stages
layers of stages - by default, stages applied across each layer elementwise
(name/number layers)
create a control for viewing/editing pipelines (not necessary named
pipelines)
- display stages
- display stage config (double-click/alt. menu)
- if editable: add/remove stages, duplicate stages, re-order stages, edit
stage configuration, save pipeline as, import from pipeline

pipeline fragmes - named bits of stages, held in storage; not directly


invokable. Templates? allow variables in some way?
text-based pipeline items?

for defaulted lambda arguments, allow captured values for the lambda to be pulled
from the eventual callsite of the function if they aren't available at declaration
time

allow multiple declarations with additive default arguments/other sig. bits

nested scope decls. reset default arg values? (not sure quite what I meant here...)

Look at XForms toolkit (X11 GUI lib, not the W3C XML format)

'where' clause - postfix operator attached to a block. Contents are a series of


statements (usually, declarations) that are executed before the original block is,
but in the same scope.

/@ & @/ for block comments? There's an argument to be made that you shouldn't
support block comments regardless, as implementing nesting for them is oft-tricky

use \( ... ) in a normal file for an inline-LISP type construct. Seems a bit odd,
but I can see it

For a 'file not found' error, print out what portions of the path are valid.
(Consider also, providing a levenshtein-based 'did you mean...' correction for
likely other paths)
Representing paths internally as an array of words, instead of as a string,
would make it easier to go about this. Also, this representation helps prevent a
lot of the more avoidable errors that come up with path APIs to do with mishandling
the strings, or using the incorrect separator, or other various things

Allow 'sealed' classes/interfaces. Once the module/package/containing interface has


been compiled, then no more subclasses/implementations are allowed for that
class/module except for those within the module.

As smalltalk, use a ';' after a message to send another message to the same subject

Use the 'with' operator to selectively re-initialize parts of an object; the object
is the LHS, and the partial initializer is the RHS

Allow specifying a 'deconstruct' 'magic method' for allowing the destructuring of


arbitrary data type (like C#). Allow deconstruction both by position, and by field
name (perhaps)
In C#, this works via 'out' parameters on a method. Could also allow for a
'reconstruct' method to allow for custom usage along the lines of the 'with'
operator mentioned earlier, for setting a literal object into the state
'switch' as an operator with the switched-on thing as the LHS and the switch-block
as the RHS

add a annotation on func. parameters to say that passing a NULL via that parameter
will auto-throw a NPE
@CallerArgumentExpression - used on a string parameter to a function, takes a
single argument which is the name of another parameter to that same function. Tells
the compiler that the string parameter should be set to the stringified version of
whatever expression was passed for the arg ref'd parameter

Some variable visibility rules (from C#) (braces open a scope):


It is illegal to refer to a local variable before its declaration. (This
seems reasonable I hope.)

It is illegal to have two local variables of the same name in the same local
variable declaration space or nested local variable declaration spaces.

Local variables are in scope throughout the entire block in which the
declaration occurs. This is in contrast with C++, in which local variables are in
scope in their block only at points after the declaration.

For every occurrence of a simple name, whether in a declaration or as part of


an expression, all uses of that simple name within the immediately enclosing local
variable declaration space must refer to the same entity.

This in general prevents something like


class C {
int x;
void M() {
// 100 lines of code
x = 20; // means "this.x";
Console.WriteLine(x); // means "this.x"
// 100 lines of code
int x = 10;
Console.WriteLine(x); // means "local x"
}
}
from being allowed. The main reason why you'd disallow that, is because if
someone moved the declaration of 'x' to the top of the scope, it would change the
meaning of the program. Note that the following is legal though, because there
aren't two different usage types in the same block
class C {
int x;
void M() {
{
// 100 lines of code
x = 20; // means "this.x";
Console.WriteLine(x); // means "this.x"
}
{
// 100 lines of code
int x = 10;
Console.WriteLine(x); // means "local x"
}
}
}

The following gives an 'interesting', if not particularly helpful error


message:
class C { static void M1() { int x2; { int x2; } } }
// Error is on inner declaration of x2
error CS0136: A local variable named 'x2' cannot be declared in
this scope because it would give a different meaning to 'x2', which is already used
in a 'parent or current' scope to denote something else
// Better version of the same
error CS0136: A local or parameter named 'x2' cannot be declared
in this scope because that name is used in an enclosing local scope to define a
local or parameter

static void M3() { { int x4; } int x4; }


// Error is on the outer declaration of x4
error CS0136: A local variable named 'x4' cannot be declared in
this scope because it would give a different meaning to 'x4', which is already used
in a 'child' scope to denote something else

// One more
class C { static void x11() {}
class N
{
static int x11;
static void M12()
{
x11();
int x13 = x11;
}
}
}
// Gives the following fantastic error message on the local def'n
of x11
error CS0135: 'x11' conflicts with the declaration 'C.N.x11'

Another intersting setup


MutableList thing1a = new MutableList(…); ImmutableList thing1a = new
ImmutableList(…);
ReadableList thing1b = thing1a; ReadableList thing2b = thing2a;

thing1a.IsFixedSize yields false


thing1a.Add(item) works

thing1b.IsFixedSize yields false


thing1a.Add(item) works

thing2a.IsFixedSize yields true


thing2a.Add(item) refuses compilation

thing2b.IsFixedSize yields true


thing2b.Add(item) throws exception

Empty says “I’m an uninitialized variant”, Nothing says “I’m an invalid object” and
Null says “I represent a value which is not known.” (ref VBScript)

When you have access to an object that represents an activation frame (active
call), consider making the 'argument' properties read-write, just to allow called
functions to do 'fun' things with the arguments of those that call them. This can
be useful, but I can also see any number of appalling things you could do with it
to break everything
var d = new Date(2003, 9, 45); = Fri Nov 14 00 :00:00 PST 2003
// Months are 0-based; days are 1-based
var d = new Date(2003, -1, 0); = Wed Nov 30 00:00:00 PST 2002

Difference between 'true' multidimensional arrays (declared like int[1,2]) and


'false' ones (declared like int[1][2]). The difference is between what is
essentially a single array with fancy indexing allowed, and an array that stores
other arrays. The first is guaranteed to be laid out linearly, the second isn't;
and so forth

The title obviously refers to “duck typing” which usually thought of as the
characteristic of a type system where what we care about is the existence of the
right “shape”; we don’t care if it is a duck, we care if it is a thing that can
quack. What I wanted to illustrate here is that JavaScript carries that concept
even farther than you might think. It’s not just “does this thing have the
properties of a duck?” It’s that in some situations, there is no by-design way to
even get a reliable answer to the question “is this a duck or not?” The JavaScript
type system is weird and I hope that anyone building a new type system these days
has the good sense to not create a situation where you cannot even reliably tell if
a string is a string.

Fun with generics: If the user writes the following interface


public interface I1<U> { void M(U i); void M(int i); }

and then goes to write the following implementation, what happens?


public class C1 : I1<int> { ... }
Just writing a default impl. of M works, as it matches correctly. However,
writing an explicit impl. for M only impls one, not the other
public class C2 : I1<int> { void I1<int>.M(int i) { ... } }

If you have both a default and an explicit impl., it is undefined which one
will get called in any particular case.

Fun with post-increment and pre-increment: when using the prefix/postfix ++/-- and
the like, this interacts in an interesting way with multiple usages of the same
variable in a function call when you don't have a defined order for evaluating
function args. It gets even more fun if your language has by-ref/by-name arguments
where an expression could potentially get evaluated multiple times.

Fun with 'On Error Resume Next' and the fact that it is statement based
On Error Resume Next
Temp = CInt(Foo.Bar(123))
Blah Temp
Print "Done"
// Blah gets called with 'Empty' (see above for empty vs. nothing and other
things)
On Error Resume Next
Blah CInt(Foo.Bar(123))
Print "Done"
// Blah doesn't get called, period

These do have the same semantics


On Error Resume Next
If Blah Then
Print "Hello"
End If
Print "goodbye"
// ------------
On Error Resume Next
If Blah Then Print "Hello"
Print "goodbye"
// Namely, they resume on 'Print "Hello"' in both cases. This is perhaps not
what you'd expect to happen

In VBScript, the following prints 10 then dies on line 3


c = 11
print c
Const c = 10

This is because constants do not technically come into scope until their
declaration happens; the backend just replaces all of the uses of the constant
before its declaration with its value. So in line 1, it creates the 'c' variable
and binds 11 to it. In line 2, the backend outputs the declared constant value for
c. Finally in line 3, it attempts to create a constant 'c', and fails, because the
name already exists

When constructing an object with at least one base class that calls a virtual
method in the constructor, the instance of the virtual method that gets called
corresponds to the class that the constructor is in; not the eventual most-
descended type that will be the end-result. Combining this with not having to call
the constructor as the first thing, and you can end up with some interesting things
happening. Can get even more fun if the virtual function in question is not
directly invoked via the constructor, but is rather invoked by a non-virtual
function called from the constructor

add a 'logical implication' binary operator - always true unless LHS is true and
RHS is false

Combining the 'primary constructor' feature with partial classes can result in
interesting things. Namely, the constructors are 'merged' together in a way, with
it being an error to have two parameters with the same name that aren't compatible
(for some definition of compatible not specified here)
To provide a body for the primary constructor, which executes after the
values are initially set, place a block after the class-name in the class body
(like 'class C { C {} }'). Having more than one body in a set of partial classes is
an error, because there isn't any good way for the compiler to figure out what
order they should be run in. One could say that the runtime will sequence them in a
deterministic but unspecified manner, though that seems like it could lead to some
confusion and other badness

Also, you can place a modifier of some sort on an annotation before you apply
it to a class with a primary constructor, or one of the constructor parameters, to
indicate that the annotation should be applied to the generated constructor, or to
the underlying field

One consideration: instead of auto-declaring fields from constructor


parameters, only keep them in-scope during initialization, and allow field names to
overlap. This also introduces a notion of a 'global initialization scope', so that
the following works
public class ConfigurationException(Configuration configuration, string
message) : Exception(message) {
private Configuration configuration = configuration;
public bool IsRemote { get; } = (var settings =
configuration.Settings)["remote"];
public bool IsAsync { get; } = settings["async"];
public override string ToString() => Message + "(" +
configuration + ")";
}
Note that each part of a partial class has its own separate scope (partial
initialization scope) since the order in which parts are executed is undefined

This also presents the idea of adding 'initializer blocks' as distinct from
the 'constructor body' blocks, introduced by the class name. An initializer block
is introduced by the keyword 'init', and they are executed in order. An initializer
block also doesn't need a primary constructor to be specified. They are also
subject to the same 'partial initialization scope' rules, where the order in which
different partials are init'd are unspecified

One interesting question is where you would put the visibility modifier if
you wanted to apply one to the primary constructor

Another possible idea: 'public class Point(int x: X, int y: Y);' as


equivalent to
public class Point(int x, int y) {
public int X { get; } = x; public int Y { get; } = y;
}
and you could put visibility qualifiers where needed.

for (int i = (int a = 0);


i < (int b = 10); // i and a in scope here
i += (int c = 1)) // i, a and b in scope here
(int d += i); // i, a and b but not c in scope here

equivalent to
{
int i = (int a = 0);
while (i < (int b = 10)) {
{ i += (int c = 1)); }
(int d += i);
}
}

use x.$x as a substitute for x["x"] perhaps

interesting question: should 'var x = a?.b.c;' be equivalent to 'var x = ((var tmp


= a) == null ? null : tmp.b).c;' or to 'var x = ((var tmp = a) == null ? null :
tmp.b.c);'? both can make sense at varying times
perhaps use ??. for the non-short-circuiting behavior?

auto-cast var-args from an array to an iterator/iterable where appropriate

Some way to specify a custom interpolation function for string interpolation

/*/ as the 'toggle-comment' operator

Console.WriteLine($@"Hello {((Func<String>) (() => {


Console.Write("What's your name? ");
return Console.ReadLine();
}))()}!");

default properties: An object can have a default property (with/without


parameters), and attempting to get/set the value of the object with something that
has the same type ass the default property, it will set the default property,
instead of altering the object. This also necessitates the addition of a 'Set'
statement or some equivalent to say 'no, I really wanted to change the object, not
its default property'. To use the one with the parameters, just index the object
like an array (or perhaps call it like a function; VB6 indexing was kinda weird)

suppose you have an object Baz with a property Table, Table has a default
parameterized property Item which returns an object that has a string property
Blah: Then this works just fine:
x = Baz.Table(1).Blah
But why? In this case we do not have enough compile-time information to
determine that we really should call Baz.Table.Item(1).Blah. The script engine has
every reason to believe that Table is a function or parameterized property of Baz.
This problem is solved by pushing it off to the implementation! The rule for
implementers of IDispatch::Invoke is if all of the following are true:
the caller invokes a property
the caller passes an argument list
the property does not actually take an argument list
that property returns an object
that object has a default property
that default property takes an argument list
then invoke the default property with the argument list. This is rather
weird, but okay

The second and third operands of the ?: operator control the type of the
conditional expression. Let X and Y be the types of the second and third operands.
Then,
If X and Y are the same type, then this is the type of the conditional
expression.
Otherwise, if an implicit conversion exists from X to Y, but not from Y to X,
then Y is the type of the conditional expression.
Otherwise, if an implicit conversion exists from Y to X, but not from X to Y,
then X is the type of the conditional expression.
Otherwise, no expression type can be determined, and a compile-time error
occurs.

Slightly differently: Let B and C be the second and third operands. Let X and
Y be the types of the second and third operands. Then,
If X and Y are the same type, then this is the type of the conditional
expression.
Otherwise, if an implicit conversion exists from B to Y, but not from C
to X, then Y is the type of the conditional expression.
Otherwise, if an implicit conversion exists from C to X, but not from B
to Y, then X is the type of the conditional expression.
Otherwise, no expression type can be determined, and a compile-time error
occurs.

delegate birds
delegate D D(D d);
D I = x=>x
D M = x=>x(x);
D K = x=>y=>x;
D L = x=>y=>x(y(y));
D S = x=>y=>z=>(x(z(y(z))));
D C = a=>b=>c=>a(c)(b);
D B = a=>b=>c=>a(c(b));

static int Fib4a(int n) {


int result = n switch {
0 => ((Func<int) (() => { Console.WriteLine("hello"); return 0; }))(),
_ => n >= 0 ? Fib4a(n - 1) + Fib4a(n - 2) : throw new
ArgumentOutOfRangeException()
};
return result
}

Consider the following code:


public class A<T1> {
public T1 a;
public class B<T2> : A<T2> {
public T1 b;
public class C<T3> : B<T3> {
public T1 c;
}
}
}

What does the following print?

class PopQuiz {
static void Main() {
A<int>.B<char>.C<bool> o = new A<int>.B<char>.C<bool>();
System.Console.WriteLine(o.a.GetType().FullName);
System.Console.WriteLine(o.b.GetType().FullName);
System.Console.WriteLine(o.c.GetType().FullName);
}
}

it does print System.Bool, System.Char, System.Int32


The reason is that the object o is really an instance of
C<int,char,bool> : B<char,bool>. And B is really defined as B<char,bool> : A<bool>
--------------------------------------
As I said already, I understood and agreed that we end up with
C<int,char,bool> (so that inside C, T1 is int, T2 is char, and T3 is bool). This is
necessary so that inside C there are separate notions of T1, T2 and T3, which you
need to have. What I didn't understand to start with was how T1 could be anything
other than int in that scenario.
The reason, as I was so dimly aware in my previous comment, is that A
and B are both carrying out two different roles, from the perspective of C. They
are containing classes, and they are also base classes. In these two roles they
have *different* type parameters. In the role as a containing class, T1 is int for
all of them, T2 is char, and T3 is bool.
So the member variable "c" is of type int because that's what T1 is at
that level.
However, C inherits from B<T3> (or, more precisely, B<T2,T3> because
the value of T2 inside the code of C is shared with the code of B). So in its role
as a *base* class, B is instantiated with T1=char and T2=bool. Since the member
variables of o come from its base classes (these aren't static variables, after
all), the "b" member variable is of type char.
And B inherits from A<T2> (no extra implicit type parameters here
because A is the top level). Remember that at this point T2 is bool, as mentioned
in the last paragraph. So in its role as a base class, A is being instantiated with
T1=bool, and so the member variable "a" is a bool.
Hence the output: Boolean, Char, Int32.
Insanely complex, but it makes perfect sense. I hereby vow never to
write code where an inner generic type inherits from its containing class with a
different type parameter!

The algorithm we use to search for a name used in the context of a type
S is as follows:
search S's type parameters
search S's accessible inner classes
search accessible inner classes of all of S's base classes, going
in order from most to least derived
S←S's outer class, start over

More fun with partials, this time, partial methods. Partial methods must go into a
partial class, must return void, and must be marked 'private'. The reason that they
must return 'void' is because of what makes them special: namely, they are not
required to have a body provided. If there is no body provided, upon compilation,
all calls to that method (plus evaluation of its arguments) will be removed. This
is why it must return void, because the call could or couldn't happen. One could
say that they can return things, and then calls will be replaced with the default
value for the appropriate type, but that seems like it might cause rather a bit of
confusion. However, if a user provides a body in another part of the partial class,
then the calls will not be elided.
The primary reason the call must be private is because otherwise there is no
guarantee that we will be able to see all of the possible calls for that method. It
is possible that if you had a whole-program-compilation model, you could catch them
all anyways, but that seems if it could even more confusing

What should this do, if it didn't emit a compiler error?


class C : IEnumerable<Giraffe>, IEnumerable<Turtle> {
IEnumerator<Giraffe> IEnumerable<Giraffe>.GetEnumerator() {
yield return new Giraffe();
}
IEnumerator<Turtle> IEnumerable<Turtle>.GetEnumerator() {
yield return new Turtle();
}
// [etc.]
}

class Program {
static void Main() {
IEnumerable<Animal> animals = new C();
Console.WriteLine(animals.First().GetType().ToString());
}
}

C# has the ability for you to implement the same interface twice, and
explicitly specify which interface you want to provide an implementation for.
Unfortunately, this does allow you to occasionally get yourself into weird
situations where the compiler can't figure out what it is you want.

I wonder if it would be possible to return a "multi-type" variable? Ie// one


that is either a Giraffe or a Turtle, but never a "Lion" or an "Alligator". To me,
at least, this code is trying to tell you that the container can hold only Giraffes
and Turtles and nothing else from the set of Animals (perhaps because storing
Giraffes and Lions in the same container leads to bad results). Enumerating
through the container should get a single aggregate set of both Turtles and
Giraffes, depending upon what was stored in there. Trying to store a Lion in that
code should fail at compile time but adding either Turtles or Giraffes should be
just fine. In that conceptual model, the "First().GetType()" call should return a
hybrid type of "Giraffe" | "Turtle" in the generic sense, but a specific "Giraffe"
or "Turtle" in the specific case depending upon the type stored in the first
element. Is there a better way to express this programatic desire? Currently, the
only way to put N siblings together is to either implement a seperate container for
each, to include the base class or to implement some middle "GirraffeAndTurtle"
class which inherits from "Animal" and from which both Turlte and Giraffe are
derived. It would be nice to have something clearer.
Maybe something notationally like:

Class C: IEnumerable<Turtle | Giraffe> {


IEnumerator<Giraffe | Turtle> IEnumerable<Giraffe |
Turtle>.GetEnumerator() {
if (current_obj is Giraffe) yield return new
Giraffe(current_obj);
if (current_obj is Turtle) yield return new
Turtle(current_obj);
else throw new
IncompatibleAnimalException();
}
}
class Program {
static void Main() {
// success
IEnumerable<Animal+> animals = new C();
// All the "giraffes"' stored in the set
IEnumerable<Giraffe> giraffes = new C();
// All the "Turtles" stored in the set
IEnumerable<Turtle> turtles = new C();
// Breaks at compile time
IEnumerable<Lion> lions = new C():
Console.WriteLine(animals.First().GetType().ToString());
}
}

scope-spillage: in certain cases where you introduce a variable inline with a


statement, it is added to the scope the statement is in. For instance,
GetCoordinates(out var x, out var y);
… // use x and y;

Note that it works a bit differently for 'if' statements and other compound
statements, as it spills into the scope of the if, not the scope containing the if
if (int.TryParse(s, out int i)) { … i … }

Another question: in the following


if ((var i = o as int?) != null) { … i … }
else if ((var s = o as string) != null) { … s … }
else if …
should 'i' be in-scope for the else blocks?

With pattern-matching/destructuring, allow types to specify a custom Match


operation
class Point {
private int x; private int y;
public Point(int x, int y) {...}
void Deconstruct(out int x, out int y) { ... }
static bool Match(Point p, out int x, out int y) ...
static bool Match(JObject json, out int x, out int y) ...
}
// o could be a point, or a JObject
if (o is Point { X is var x, Y is 0 }) ...

Add an option for declaring what things a lambda/nested class would capture, and
whether it captures by reference or by value

In a switch statement, allow specifying 'goto case' to jump to a specific case,


instead of doing a break
When specifying constraints on a generic parameter, specify a constraint of the
form 'new(...)' with the body being a method header to say that any provided type
must have a constructor with the provided parameters

With partial methods, allow having multiple implementations, which are called in a
deterministic-but-unspecified manner.
For another usage of the partial keyword, put it on a field in a partial
class to say 'I have additional annotations I wish to place on this field, but its
declaration is in a different partial member that I cannot edit'

Another interesting note on partial classes: When you have multiple classes
marked as being inherited from on the parts, if you inherit from both a class and
one of its subclasses, remove the inheritance from the class to clear away a
potential diamond-base problem.

'goes toward' operator: x --> y (think of it as x-- > y, when properly spaced)

class C {
private string x;
public string X {
get { return x ?? ""; }
set { x = value; }
}
static void Main() {
C c = new C();
object z;
z = c.X = null;
System.Console.WriteLine(z == null);
System.Console.WriteLine(c.X == null);
}
}
This prints “True / False”, which may not be what you were expecting to
happen.

When using 'new', allow omitting empty constructor arg-lists. This does mean that
the following code is interesting
class C { public C() {...}; public C B() {...}; class B { public B() {...} }}

Should 'new C.B' create a new instance of C, and then invoke B, or should it
create a new instance of C.B? Combined with certain other features, this can get
even more hairy

Another fun one: virtual methods and calling grandparents. Lets say you have the
following code
class A {
public void x() {
// do some stuff...
y();
}
public void y() {
// do some more things, assuming that the work in x() was done
...
}
}
class B : A {
public void x() {
// Do some other things, different than what happened in the A
version
...
y();
}
public void y() {
// Do something, assuming that the work we did in our version
happened
...
}
}

Then, you want to introduce the following class


class C : B {
public void x() {
....
}
}
The issue; you want to call the version of x that A implements from your copy
of x. That in itself, is not the issue. What is the issue, is that the version of x
in A, calls the y method. If we dispatch that as a virtual call, the copy of y in B
gets called, without the work that should've happened in B's version of x
happening. Oops.

Look up things for the CURL language

Some sort of method or function qualifier to indicate 'This method will never
return normally'. Generally, that means that it will either throw an exception, or
do something else to interrupt the normal control flow.
Could make the indicator a special type 'never', which is similar to void

The following emits a warning that the value of the default parameter will be
ignored, since it can't easily be known based off of the type
interface IAbc { void M(int x) {} }
class Abc : IAbc { void IAbc.M(int x = 123) {} }

Another fun one:


interface IABC { void M(bool x = true); }
interface IXYZ { void M(bool x = false); }
class C : IABC, IXYZ { public void M(bool x) {} }
What happens if you say 'C x = new C(); x.M();'? You get an overload
resolution error, since the compiler has no idea which default parameter it should
be using, so it says you need to explicitly provide the missing parameter

Look at IDispatch/IDispatchEx for potentially interesting things


// We now have the following problem. We have "foo.bar(".
// What if bar returns an object that has a default property?
// Suppose bar is a collection, for instance, with a default
// property "item". Then this should show statement completion
// information for the "item" method, not for "bar" -- provided
// that bar takes no arguments. If bar takes arguments, then
// we should show statement completion for bar.
// This generalizes to chains of defaults -- if bar is the default
// property of foo, and bar takes no arguments, and bar
// returns an object that has default property baz that takes
// an argument blah, then
//
// foo(
// foo.bar(
// foo.bar.baz(
//
// should all return statement completion information for baz(blah).
//
// So here's what we'll do:
// First we determine if "bar" returns an object. If it does,
// we check and see if it has a default property chain. If so, we
// get type info for the final available function on the default
// property chain.
// Second, if bar is a function that takes arguments, we return
// function information for bar.
// If bar does not take arguments and bar returns an object with
// a default property, then we return info on the default property.
// Otherwise, we return information on bar.
//
// This is not actually what Visual Basic does. VB does the
// following: (from email by Matt Curland, 1998-03-27)
//
// "If no parameters are supplied never call the default unless
// you're in an assignment statement without a Set. If you're
// in a non-ending statement of a call chain then only do
// the default resolution if the specified function doesn't have
// its own parameters and a parameter is actually specified."
//
// That is not exactly what we're doing here, but it's close enough
// as far as I'm concerned.

It is possible for an object to be destructed on the finalizer thread while its


constructor is running in a user thread!

Pattern matching syntaxes:


if (s is ExpressionStatement e &&
e.Expr is AssignmentExpressionSyntax a &&
a.Left is IdentifierName l &&
a.Right is IdentifierName r &&
l.Name.name == r.Name.name)

if (s is ExpressionStatement {
Expr is AssignmentExpressionSyntax {
Left is IdentifierName { Name is val l },
Right is IdentifierName { Name is val r } } }
&& l.name = r.name

if (s is ExpressionStatement(
AssignmentExpressionSyntax(IdentifierName l, IdentifierName r))
&& l.name = r.name)

case (int age, string name):


case (string name, int age):
WriteLine($"{name} is {age} years old.");
break;

It is tempting to ponder generalizations of goto case x. For instance, maybe


you could do the whole switch again, but on the value x. That's interesting, but
comes with lots of complications and hidden performance traps. Also it is probably
not all that useful.

Flexible types (#type) - This allows you to say 'I want a type like this other
type' in certain circumstances where using an ordinary constrained generic
parameter wouldn't work correctly. Equivalent to
#SomeType
or
'T when 'T :> SomeType

Perhaps do something interesting with 'active patterns' (F#)

use !! as a suffix on a parameter to indicate both that the compiler check its not
null, and to have a runtime check

Some interesting ideas from ISupportInitialize: the idea behind seems to be that
you say "I'm going to set a whole bunch of properties on this object; hold off on
any validation or other things until I'm done"

Do something interesting with AggregateException: one idea I remember seeing is


having catch blocks able to catch the individual exceptions, but the exception will
still be thrown until all of its sub-parts are handled

size vs. length vs. count

guard statement
void M(object o) {
guard (o is int i) else throw new ArgumentException("Not an int",
nameof(o)); // else must leave scope
...i...; // i is in scope because the guard statement is specially leaky
}

Look at python Trio for an interesting async idea

Different types of blocks require different brace syntaxes


for (something)
{
}

do
{{
// something
}}

while (foo)
{{{
// something
}}}

if (something)
}
// do something
{

hope // 'hope' is the replacement for 'try'


{}
// something
{}
bucket 'bucket' is the replacement for catch (the reason is, 'throw' was
replaced with hurl/throwUp)
{}
// eww.
{}

Classes are split into 'interfaces' and 'materialization' of those interfaces


the interface of a class presents two facets: the 'forge' of the class, being
the set of non-private constructor signatures; and its type, the set of externally-
accessible fields and methods as well as available cast operations. The
materialization of a class has three facets: the implementation, i.e., the method
bodies; the mill, being the implementation of the forge; and the mold, which is the
memory layout used for creating objects

Reference: 'Shakeins' as an alternative for Aspect-Oriented-Programming

Something to do with the way that Go handles 'nil', where you have both typed nils,
which specify that you don't have a value of that particular type; and you also
have untyped nils, which specify that not only do you not have a value, you don't
even know what type it was supposed to be.
The specific case where this comes up a lot in Go is dealing with interfaces;
where Go tracks both the value for the interface, as well as the actual concrete
type of that value. Passing a raw nil there will give you an untyped nil, where as
passing a typed variable that happens to be nil will give you a typed one.

A programming language would provide us with a structure that would act like an
array of structs, but internally it would really behave like a struct of arrays

Displaced arrays are a construct in COMMON LISP borrowed from FORTRAN. It is


possible to alias two arrays to the same storage locations. That is, it is
possible to state that the array elements A(0)–A(j) are identical to the array
elements B(k)–B(l) where A and B are arrays and j=l−k. Notice that A and B may
overlap with some elements of B not part of A if k0.

mapWithBothSides takes a function of three arguments and a list, and returns a list
of applying the function for all three-tuples consisting of an initial prefix, the
next element, and the remaining suffix

Perhaps do something similar to Clojure's get-in?

Excel LET
= LET(
\0, "Generate indices",
N, COUNTIF(Project[Working Area],Criterion),
k, SEQUENCE(8*N,1,0),
recordOffset, QUOTIENT(k,8),
fieldOffset, MOD(k,8),
\1, "Filter fields and records to extract relevant data",
headers, FILTER(Project[#Headers],columnFilter),
selectedFields, FILTER(Project, columnFilter),
filteredKey, FILTER(Project[Projeto], Project[Working
Area]=Criterion),
filteredTable, FILTER(selectedFields, Project[Working
Area]=Criterion),
\2, "Assemble report recombining project key and selected data",
reportKey, INDEX(filteredKey, 1+recordOffset),
reportHeader, IF(fieldOffset, INDEX(headers, 1+fieldOffset),
reportKey),
reportData, INDEX(filteredTable, 1+recordOffset, 1+fieldOffset),
report, CHOOSE({1,2}, reportHeader, reportData),
report )

It filters a table using a single criterion, selects specified fields to


return and pivots them to fit a vertically formatted sequence of reports and,
finally, adds the project heading for each report and row headings for the data
values. Maybe too much for a single formula?
In C99, static has gained another use, e.g. int Y(int a[static 10]); which means
that there is a function Y which takes an array of at least 10 integers.

Implement something like scanf returning an Object[] in Java?

Fun with inner classes


class A{class B extends A{B.B.B b;}}
A has an inner class B. This means we can declare a variable of type A.B.
But B is a subclass of A, which means it has all of the methods, fields, and
inner classes of A. Thus, we can refer to the type B.B as well. In this code, we
take this a step further, and give B an instance variable of type B.B.B.

The moral: following hot questions on SO can teach you a lot of interesting,
if pointless, techniques.

// infamous `requires requires`. First `requires` is requires-clause, second one is


requires-expression. useful if you don't want to introduce new concept.
template<typename T> requires requires(T a, T b) {a + b;}
auto f4(T x);

Add a 'autoclosure' attribute in function declarations to specify that certain


arguments automatically get converted into lambda-expressions; this is pretty much
the same as converting that argument from eagerly evalutated, to lazily evaluated

Allow use of 'break/continue' in a statement context where it does what you might
think when evaluated

Use the 'ascribe' keyword for determining which part of a sum type you are
returning, when you have a sum-type which has two values of the same type (like T +
T)

'var' behavior is indicated with '[...]' as a declarator. Behavior is like a


container, and associates additional functionality with reading/writing the
variable.

For functions which take a struct as the last argument, allow named arguments to
auto-create and initialize the fields for said struct

Use 'director'/'worker' instead of 'master'/'slave' to avoid unfortunate


connotations.

Something using '&&=' and '||=' as 'boolean coalescing' assignment. Ex:


a = true; b = false; c = false;
a ||= b; // a is still true, because a || b is true
a &&= b // a is now false, because a && b is false
a &&= c // Open question: should c be evaluated? because it can't possibly
change the state of a

we wrote REDUCE(), a hypothetical one, like this:


1, 2, 3, 4, 5

with t(i) as (values (2), (4), (3), (1), (6), (5))


select reduce(
t1.i * t2.i referencing accumulated as t1, accumulating as t2
)
from t;
This is SQL, so the lambda expression would obviously use a ton of keywords,
completely novel and unique to this particular function
some sort of reduction expression based on two pseudo tables:
The accumulated table containing the result
The accumulating table (or rather row)

Designated-base-class initialization for structs


// Declare some structs
template <typename T> struct C { T val; };
struct D : C<int>, C<char> { };

// Create an instance of the struct. Note how both of the base objects are
initialized
D{:C<int>={.val=1}, :C<char>={.val='x'}};
// With generic base classes, if it's unambiguous what the parameters of the
type should be, you can leave them out
D{:C{.val=1}};

// Note that this can occasionally lead to some confusion on the part of
users as to the designated type
namespace N { template <typename T> struct C { }; }
struct D : N::C<int> { };
using C = N::C<double>;

// This C refers to the base-type of D, because that is the only sensible


thing for it to refer to.
D{:C{}};

Consider allowing 'x |> f(y)' to refer to 'f(x, y)' (as a rewrite)
The reason this is specified as a rewrite is because allowing it as a
specific operator can lead to some strangeness where people have to write the
explicit form twice, instead of writing it once, and letting the implicit version
handle the other one

SliceIterator, based off of ListIterator


MemoIterator, a ListIterator backed by a normal iterator, which uses memoization to
allow iterating back over them

VimL list unpacking


To unpack the items in a list to individual variables, put the variables in
square brackets, like list items:
:let [var1, var2] = mylist
When the number of variables does not match the number of items in the list
this produces an error. To handle any extra items from the list append ";"
and a variable name:
:let [var1, var2; rest] = mylist
This works like:
:let var1 = mylist[0]
:let var2 = mylist[1]
:let rest = mylist[2:]
Except that there is no error if there are only two items. "rest" will be an
empty list then.

Semi-interesting idea: Instead of having a single concept of 'iterators' which


allows you to both traverse and access the properties of a collection, split the
responsibilities among two concepts: 'cursors' and 'property maps'. Cursors allow
you to determine a specific position within a collection, while 'property maps'
allow you to take a position obtained from a cursor, and get an item from the
collection.
Note that 'position' doesn't imply an integer position of some sort. It is
instead a special type known as a 'key type' which is specific to that particular
cursor, and only really usable on the given property map.
With type deduction/inference, allow a type to specify something inside it to
indicate that whenever you would infer this type, you should infer some other type
instead. The most productive use case for this is when you have a function that for
various reasons returns a type internal to your library for some reason, and it is
perfectly fine to pass that type to other functions in your library, or store into
a variable which explicitly names the type in question. However, if someone
attempts to store it into a deduced variable, the type of the variable will instead
be set to some external type, and a conversion will be triggered from the internal
type to the external type. The most common use case is proxy types of varying
sorts, where you almost never want to directly talk about the proxy as a proxy, but
instead as the application it is a proxy for.
One proposed syntax for C++ was something like
struct A {...}
struct B { ... using auto= A} // Indicates that you should deduce A
whenever you would deduce B.

A f(A x);
A f(B x);
B g(A x);

A x = new A() // x contains a new A now


B y = new B() // y contains a new B now
auto z = new B() // creates a new B, and then triggers whatever
conversion from B to A is defined.
explicit auto zz = new B() // zz contains a new B now, since you said
you explicitly wanted the exact type.
auto xx = f(new A()) // Triggers the overload of f that takes an A, and
xx contains an A now
auto yy = f(new B()) // Triggers the overload of f that takes a B, and
yy contains the result of triggering the conversion on the resulting value
auto h = g(new B()) // Triggers the overload of g that takes an A,
triggering the conversion on both the argument and the return value

Bad JS code involving switches


switch (!0) {
case (createAccountForm = forms.filter(createAccountForm), !!
createAccountForm.length):
createAccountFormFn(createAccountForm);
processQueryString(createAccountForm);
break;
case (addNewProperty = forms.filter(addNewProperty), !!
addNewProperty.length):
addNewPropertyFn(addNewProperty); processQueryString(addNewProperty);
break;
case (!!templates.length && templates.is(contactUsFormTemplate)):
contactUsFn(forms);
break;
case (!!templates.length && templates.is(loginFormTemplate)):
loginFn(forms);
break;
case (!!templates.length && templates.is(forgotPassTemplate)):
forgotPassFn(forms);
break;
case (!!templates.length && templates.is(GetSecurityQuestionTemplate)):
resetPasswordFn(forms);
break;
};
Look into C#/Roslyn ISourceGenerator and ISyntaxReceiver

With switch statement cases, use different delimiters to indicate that the body of
a case has a different context
=> body executed in new scope, should return a value
-> body executed in new scope, shouldn't return a value
: body executed in existing scope, shouldn't return a value; should leave the
block

Allow declaring variables as 'auto x'; then, as long as the first usage of x is in
a context where it is being written to (or in a context where it's type is
otherwise defined) then its type is determined there. Otherwise, you get a compiler
error about 'no type deduced for variable x' or 'attempted to use variable x when
its type was not yet determined'

You might also like