Difference between revisions of "User:Enamex/DIP: User Defined Active Patterns"

From D Wiki
Jump to: navigation, search
(Created page with "{| class="wikitable" !Title: !'''DIP Template''' |- |DIP: |xx |- |Version: |0.1 |- |Status: |Draft |- |Created: |2015-09-04 |- |Last Modified: |{{REVISIONYEAR}}-{{REVISIONMONT...")
 
m
 
(3 intermediate revisions by the same user not shown)
Line 40: Line 40:
 
== Usage ==
 
== Usage ==
 
<syntaxhighlight lang="d">
 
<syntaxhighlight lang="d">
module superb.a;
 
struct Tile {
 
    void scan() {}
 
}
 
</syntaxhighlight>
 
 
 
<syntaxhighlight lang="d">
 
module superb.call.util;
 
 
import superb.a;
 
 
// anonymous extension interface, attached to struct superb.a.Tile
 
interface (Tile) {
 
    bool detectChell() { return true; }
 
}
 
 
// named extension interface 'prototype'; later implemented by types and tested against;
 
// could also support using any interface this way, and dropping the `()` in declaration
 
interface () HydraulicMobileEnvironment
 
    : path.SomeOtherInterfaceInherited // inheritance of extension interfaces allowed
 
{
 
    static immutable int startingHealth;
 
    bool smash_opposite_tiles() { return true; }
 
}
 
</syntaxhighlight>
 
 
 
<syntaxhighlight lang="d">
 
module superb.core;
 
 
import superb.a: Tile;
 
import superb.call.util: HydraulicMobileEnvironment;
 
 
// implement extension interface 'HydraulicMobileEnvironment' for type Tile
 
interface (Tile)
 
    : HydraulicMobileEnvironment
 
{
 
    // provided required implementation, uses default of 'smash_opposite_tiles'
 
    static immutable int startingHealth = 95;
 
}
 
</syntaxhighlight>
 
 
 
<syntaxhighlight lang="d">
 
module superb.mainfunc;
 
 
import superb.a;
 
import superb.core;
 
 
 
void main() {
 
void main() {
     Tile t;
+
     Option!int x = ???;
     t.smash_opposite_tiles(); // works; 'superb.core.HydraulicMobileEnvironment' implementation for 'superb.a.Tile';
+
     #match(x) {
                              // error if 'superb.core.HydraulicMobileEnvironment' is not imported;
+
        Some(v): { writeln(v); }
                              // You import the interface declaration,
+
        default: {}
                              // not the implementation (which is automatically available unless declared private)
+
     }
    t.scan(); // native definition
 
     t.detectChell(); // function in anonymous extension interface; doesn't require importing anything for it
 
 
}
 
}
</syntaxhighlight>
 
  
 +
struct Option(T) {
 +
    struct Some {
 +
        T value_;
 +
    }
 +
   
 +
    struct None {}
  
Alternative syntax:
+
    enum Tag { Some, None }
<syntaxhighlight lang="d">
+
     Tag Tag_;
alias struct ForeignStructToBeExtended {
 
     /* add methods/static functions and constants here;
 
      they become a part of `ForeignStructToBeExtended`
 
      wherever `ForeignStructToBeExtended` is in scope
 
      in the super of the package that defines the struct/class.
 
    */
 
}
 
  
alias interface ExtensionInterface {
+
    union UD {
     /* An 'extension interface' declared as `alias interface`
+
        Some Some_;
      is 'inherited' from by either a local type if the alias
+
        None None_;
      interface is foreign; or a foreign type if the alias
+
     }
      interface is local to the super package.
+
    UD ud;
    */
+
   
}
+
    Tuple!(bool, Some*) opMatch(string op: "Some") {
 +
        if( Tag_ == Tag.mixin(op) ) {
 +
            return std.typecons.tuple(true, &ud.mixin(op~"_").value_);
 +
        }
 +
        else return std.typecons.tuple(false, null);
 +
    }
  
// `alias interface` is implemented for a struct/class by the syntax:
+
    Tuple!(bool, None*) opMatch(string op: "None") {
alias struct StructImplementingExtension
+
        if( Tag_ == Tag.mixin(op) ) {
    : ExtensionInterface
+
            return std.typecons.tuple(true, &ud.mixin(op~"_")));
{
+
        }
     /*methods and stuff*/
+
        else return std.typecons.tuple(false, null);
 +
     }
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>

Latest revision as of 21:37, 10 September 2015

Title: DIP Template
DIP: xx
Version: 0.1
Status: Draft
Created: 2015-09-04
Last Modified: 2015-09-10
Author: Enamex(:real-name)
Links:

Abstract

(quick jot down; not final abstract); Proposal to add a match keyword and an auto opMatch(string pattern: "myPattern")(typeof(this) matobj) class/struct method and free function that takes as the only argument the object being de-structured and returns a Tuple containing the patterns assignable hooks. The compiler then rewrites invocations to the specific active pattern function into a series of declarations of the variables in user code inited with the returned parts of the chosen opMatch.

Description

Allow the declaration of extension interfaces that accept function prototypes (with optional default implementations) and associated constants (both `static immutable` and manifest constants allowed) and the implementation of such interfaces for a `struct` or `class` after its definition.

Extension interfaces defined under the user's most super package would be implementable for types provided in third-party packages/libraries. Types defined under the user's most super package would be able to implement extension interfaces provided in third-party package/libraries.

It is impossible for a package to implement a third-party extension interface for a third-party type.

In any sub-module of the most super package of a project, any local type or extension interface that has been coupled with a local or foreign extension interface or type would behave as if the type natively possesses all functions and associated constants defined in the implemented extension interfaces. All functions in the type-implemented extension interfaces would be callable through method syntax `object.method()` and visible throughout the package no matter where the implementation block lies (it must still be under the same most super package, however).

Usage

void main() {
    Option!int x = ???;
    #match(x) {
        Some(v): { writeln(v); }
        default: {}
    }
}

struct Option(T) {
    struct Some {
        T value_;
    }
    
    struct None {}

    enum Tag { Some, None }
    Tag Tag_;

    union UD {
        Some Some_;
        None None_;
    }
    UD ud;
    
    Tuple!(bool, Some*) opMatch(string op: "Some") {
        if( Tag_ == Tag.mixin(op) ) {
             return std.typecons.tuple(true, &ud.mixin(op~"_").value_);
        }
        else return std.typecons.tuple(false, null);
    }

    Tuple!(bool, None*) opMatch(string op: "None") {
        if( Tag_ == Tag.mixin(op) ) {
             return std.typecons.tuple(true, &ud.mixin(op~"_")));
        }
        else return std.typecons.tuple(false, null);
    }
}

Recommendations

When writing a DIP, try not to express your opinion. DIPs should provide facts and be as objective as possible. Even when that's pretty hard, you can make the DIP look more objective by not using, for example, "I prefer XXX because YYY". If YYY is an objective advantage, write that in a more objective way, like "XXX can be a better option because YYY". Try to leave non-technical personal preferences aside; "XXX can be a better option because the syntax is nicer" is not good enough even when you don't say "I prefer".

Try not to include half-baked ideas. If you are not sure about something, leave it outside the DIP and write it on the NG announcement instead for further discussion. The idea can be added to the DIP in the future when it is in a better shape.

NG Announcement

When posting the DIP announcement to the NG, please copy the abstract, so people can easily know what is it about and follow the link if they are interested.


Copyright

This document has been placed in the Public Domain.