Patch 9.0.1053
Problem:    Default constructor arguments are not optional.
Solution:   Use "= v:none" to make constructor arguments optional.
Files:      runtime/doc/vim9class.txt, src/errors.h, src/userfunc.c,
            src/vim9class.c, src/vim9compile.c, src/vim9execute.c,
            src/vim9instr.c, src/proto/vim9instr.pro, src/vim9.h,
            src/testdir/test_vim9_class.vim


*** ../vim-9.0.1052/runtime/doc/vim9class.txt   2022-12-08 15:32:11.075034154 
+0000
--- runtime/doc/vim9class.txt   2022-12-13 18:41:05.293974808 +0000
***************
*** 96,102 ****
              this.col = col
           enddef
         endclass
! 
  You can create an object from this class with the new() method: >
  
        var pos = TextPosition.new(1, 1)
--- 96,102 ----
              this.col = col
           enddef
         endclass
! <                                                     *object* *Object*
  You can create an object from this class with the new() method: >
  
        var pos = TextPosition.new(1, 1)
***************
*** 104,110 ****
  The object members "lnum" and "col" can be accessed directly: >
  
        echo $'The text position is ({pos.lnum}, {pos.col})'
! 
  If you have been using other object-oriented languages you will notice that
  in Vim the object members are consistently referred to with the "this."
  prefix.  This is different from languages like Java and TypeScript.  This
--- 104,110 ----
  The object members "lnum" and "col" can be accessed directly: >
  
        echo $'The text position is ({pos.lnum}, {pos.col})'
! <                                                     *E1317* *E1327*
  If you have been using other object-oriented languages you will notice that
  in Vim the object members are consistently referred to with the "this."
  prefix.  This is different from languages like Java and TypeScript.  This
***************
*** 329,342 ****
  
  ==============================================================================
  
! 5.  More class details                                        *Vim9-class*
  
  Defining a class ~
                                        *:class* *:endclass* *:abstract*
  A class is defined between `:class` and `:endclass`.  The whole class is
  defined in one script file.  It is not possible to add to a class later.
  
! A class can only be defined in a |Vim9| script file.  *E1315*
  A class cannot be defined inside a function.
  
  It is possible to define more than one class in a script file.  Although it
--- 329,342 ----
  
  ==============================================================================
  
! 5.  More class details                                *Vim9-class* *Class* 
*class*
  
  Defining a class ~
                                        *:class* *:endclass* *:abstract*
  A class is defined between `:class` and `:endclass`.  The whole class is
  defined in one script file.  It is not possible to add to a class later.
  
! A class can only be defined in a |Vim9| script file.  *E1316*
  A class cannot be defined inside a function.
  
  It is possible to define more than one class in a script file.  Although it
***************
*** 361,367 ****
                                                        *E1314*
  The class name should be CamelCased.  It must start with an uppercase letter.
  That avoids clashing with builtin types.
! 
  After the class name these optional items can be used.  Each can appear only
  once.  They can appear in any order, although this order is recommended: >
        extends ClassName
--- 361,367 ----
                                                        *E1314*
  The class name should be CamelCased.  It must start with an uppercase letter.
  That avoids clashing with builtin types.
!                                                       *E1315*
  After the class name these optional items can be used.  Each can appear only
  once.  They can appear in any order, although this order is recommended: >
        extends ClassName
***************
*** 377,382 ****
--- 377,396 ----
  interface, which is often done in many languages, especially Java.
  
  
+ Items in a class ~
+                                               *E1318* *E1325* *E1326*
+ Inside a class, in betweeen `:class` and `:endclass`, these items can appear:
+ - An object member declaration: >
+       this._memberName: memberType
+       this.memberName: memberType
+       public this.memberName: memberType
+ - A constructor method: >
+       def new(arguments)
+       def newName(arguments)
+ - An object method: >
+       def SomeMethod(arguments)
+ 
+ 
  Defining an interface ~
                                                *:interface* *:endinterface*
  An interface is defined between `:interface` and `:endinterface`.  It may be
***************
*** 417,427 ****
  
  Then The default constructor will be: >
  
!       def new(this.name, this.age, this.gender)
        enddef
  
  All object members will be used, also private access ones.
  
  
  Multiple constructors ~
  
--- 431,462 ----
  
  Then The default constructor will be: >
  
!       def new(this.name = v:none, this.age = v:none, this.gender = v:none)
        enddef
  
  All object members will be used, also private access ones.
  
+ The "= v:none" default values make the arguments optional.  Thus you can also
+ call `new()` without any arguments.  No assignment will happen and the default
+ value for the object members will be used.  This is a more useful example,
+ with default values: >
+ 
+       class TextPosition
+          this.lnum: number = 1
+          this.col: number = 1
+       endclass
+ 
+ If you want the constructor to have mandatory arguments, you need to write it
+ yourself.  For example, if for the AutoNew class above you insist on getting
+ the name, you can define the constructor like this: >
+ 
+       def new(this.name, this.age = v:none, this.gender = v:none)
+       enddef
+ <                                                     *E1328*
+ Note that you cannot use another default value than "v:none" here.  If you
+ want to initialize the object members, do it where they are declared.  This
+ way you only need to look in one place for the default values.
+ 
  
  Multiple constructors ~
  
*** ../vim-9.0.1052/src/errors.h        2022-12-09 21:41:43.904327284 +0000
--- src/errors.h        2022-12-13 15:46:28.110463023 +0000
***************
*** 3372,3375 ****
--- 3372,3377 ----
        INIT(= N_("E1326: Member not found on object \"%s\": %s"));
  EXTERN char e_object_required_found_str[]
        INIT(= N_("E1327: Object required, found %s"));
+ EXTERN char e_constructor_default_value_must_be_vnone_str[]
+       INIT(= N_("E1328: Constructor default value must be v:none: %s"));
  #endif
*** ../vim-9.0.1052/src/userfunc.c      2022-12-10 18:42:09.094378801 +0000
--- src/userfunc.c      2022-12-13 17:05:23.549043681 +0000
***************
*** 224,230 ****
      char_u    *p;
      int               c;
      int               any_default = FALSE;
-     char_u    *expr;
      char_u    *whitep = *argp;
  
      if (newargs != NULL)
--- 224,229 ----
***************
*** 302,307 ****
--- 301,334 ----
            arg = p;
            while (ASCII_ISALNUM(*p) || *p == '_')
                ++p;
+           char_u *argend = p;
+ 
+           if (*skipwhite(p) == '=')
+           {
+               char_u *defval = skipwhite(skipwhite(p) + 1);
+               if (STRNCMP(defval, "v:none", 6) != 0)
+               {
+                   semsg(_(e_constructor_default_value_must_be_vnone_str), p);
+                   goto err_ret;
+               }
+               any_default = TRUE;
+               p = defval + 6;
+ 
+               if (ga_grow(default_args, 1) == FAIL)
+                   goto err_ret;
+ 
+               char_u *expr = vim_strsave((char_u *)"v:none");
+               if (expr == NULL)
+                   goto err_ret;
+               ((char_u **)(default_args->ga_data))
+                                                [default_args->ga_len] = expr;
+               default_args->ga_len++;
+           }
+           else if (any_default)
+           {
+               emsg(_(e_non_default_argument_follows_default_argument));
+               goto err_ret;
+           }
  
            // TODO: check the argument is indeed a member
            if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
***************
*** 309,315 ****
            if (newargs != NULL)
            {
                ((char_u **)(newargs->ga_data))[newargs->ga_len] =
!                                                   vim_strnsave(arg, p - arg);
                newargs->ga_len++;
  
                if (argtypes != NULL && ga_grow(argtypes, 1) == OK)
--- 336,342 ----
            if (newargs != NULL)
            {
                ((char_u **)(newargs->ga_data))[newargs->ga_len] =
!                                              vim_strnsave(arg, argend - arg);
                newargs->ga_len++;
  
                if (argtypes != NULL && ga_grow(argtypes, 1) == OK)
***************
*** 322,336 ****
                    if (ga_grow(newlines, 1) == OK)
                    {
                        // "this.name = name"
!                       int len = 5 + (p - arg) + 3 + (p - arg) + 1;
                        char_u *assignment = alloc(len);
                        if (assignment != NULL)
                        {
!                           c = *p;
!                           *p = NUL;
!                           vim_snprintf((char *)assignment, len,
                                                     "this.%s = %s", arg, arg);
!                           *p = c;
                            ((char_u **)(newlines->ga_data))[
                                              newlines->ga_len++] = assignment;
                        }
--- 349,370 ----
                    if (ga_grow(newlines, 1) == OK)
                    {
                        // "this.name = name"
!                       int len = 5 + (argend - arg) + 3 + (argend - arg) + 1;
!                       if (any_default)
!                           len += 14 + 10;
                        char_u *assignment = alloc(len);
                        if (assignment != NULL)
                        {
!                           c = *argend;
!                           *argend = NUL;
!                           if (any_default)
!                               vim_snprintf((char *)assignment, len,
!                                               "ifargisset %d this.%s = %s",
!                                          default_args->ga_len - 1, arg, arg);
!                           else
!                               vim_snprintf((char *)assignment, len,
                                                     "this.%s = %s", arg, arg);
!                           *argend = c;
                            ((char_u **)(newlines->ga_data))[
                                              newlines->ga_len++] = assignment;
                        }
***************
*** 361,367 ****
                // find the end of the expression (doesn't evaluate it)
                any_default = TRUE;
                p = skipwhite(np + 1);
!               expr = p;
                if (eval1(&p, &rettv, NULL) != FAIL)
                {
                    if (!skip)
--- 395,401 ----
                // find the end of the expression (doesn't evaluate it)
                any_default = TRUE;
                p = skipwhite(np + 1);
!               char_u *expr = p;
                if (eval1(&p, &rettv, NULL) != FAIL)
                {
                    if (!skip)
*** ../vim-9.0.1052/src/vim9class.c     2022-12-10 18:42:09.090378817 +0000
--- src/vim9class.c     2022-12-13 17:10:48.921759464 +0000
***************
*** 269,274 ****
--- 269,275 ----
                ga_concat(&fga, (char_u *)"this.");
                objmember_T *m = cl->class_obj_members + i;
                ga_concat(&fga, (char_u *)m->om_name);
+               ga_concat(&fga, (char_u *)" = v:none");
            }
            ga_concat(&fga, (char_u *)")\nenddef\n");
            ga_append(&fga, NUL);
*** ../vim-9.0.1052/src/vim9compile.c   2022-12-10 18:42:09.090378817 +0000
--- src/vim9compile.c   2022-12-13 17:01:53.268332112 +0000
***************
*** 2195,2202 ****
   * Return "arg" if it does not look like a variable list.
   */
      static char_u *
! compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
  {
      char_u    *var_start;
      char_u    *p;
      char_u    *end = arg;
--- 2195,2207 ----
   * Return "arg" if it does not look like a variable list.
   */
      static char_u *
! compile_assignment(
!       char_u      *arg_start,
!       exarg_T     *eap,
!       cmdidx_T    cmdidx,
!       cctx_T      *cctx)
  {
+     char_u    *arg = arg_start;
      char_u    *var_start;
      char_u    *p;
      char_u    *end = arg;
***************
*** 2206,2211 ****
--- 2211,2217 ----
      int               semicolon = 0;
      int               did_generate_slice = FALSE;
      garray_T  *instr = &cctx->ctx_instr;
+     int               jump_instr_idx = instr->ga_len;
      char_u    *op;
      int               oplen = 0;
      int               heredoc = FALSE;
***************
*** 2216,2221 ****
--- 2222,2244 ----
      lhs_T     lhs;
      long      start_lnum = SOURCING_LNUM;
  
+     int               has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) 
== 0;
+     if (has_arg_is_set_prefix)
+     {
+       arg += 11;
+       int def_idx = getdigits(&arg);
+       arg = skipwhite(arg);
+ 
+       // Use a JUMP_IF_ARG_NOT_SET instruction to skip if the value was not
+       // given and the default value is "v:none".
+       int off = STACK_FRAME_SIZE + (cctx->ctx_ufunc->uf_va_name != NULL
+                                                                     ? 1 : 0);
+       int count = cctx->ctx_ufunc->uf_def_args.ga_len;
+       if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_NOT_SET,
+                                               def_idx - count - off) == FAIL)
+           goto theend;
+     }
+ 
      // Skip over the "varname" or "[varname, varname]" to get to any "=".
      p = skip_var_list(arg, TRUE, &var_count, &semicolon, TRUE);
      if (p == NULL)
***************
*** 2636,2641 ****
--- 2659,2671 ----
  
        if (var_idx + 1 < var_count)
            var_start = skipwhite(lhs.lhs_end + 1);
+ 
+       if (has_arg_is_set_prefix)
+       {
+           // set instruction index in JUMP_IF_ARG_SET to here
+           isn_T *isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
+           isn->isn_arg.jumparg.jump_where = instr->ga_len;
+       }
      }
  
      // For "[var, var] = expr" drop the "expr" value.
***************
*** 2711,2719 ****
        }
      }
  
!     if (*eap->cmd == '[')
      {
-       // might be "[var, var] = expr"
        *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
        if (*line == NULL)
            return FAIL;
--- 2741,2749 ----
        }
      }
  
!     // might be "[var, var] = expr" or "ifargisset this.member = expr"
!     if (*eap->cmd == '[' || STRNCMP(eap->cmd, "ifargisset ", 11) == 0)
      {
        *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
        if (*line == NULL)
            return FAIL;
***************
*** 2994,3000 ****
        int     count = ufunc->uf_def_args.ga_len;
        int     first_def_arg = ufunc->uf_args.ga_len - count;
        int     i;
-       char_u  *arg;
        int     off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
        int     did_set_arg_type = FALSE;
  
--- 3024,3029 ----
***************
*** 3002,3024 ****
        SOURCING_LNUM = 0;  // line number unknown
        for (i = 0; i < count; ++i)
        {
            type_T      *val_type;
            int         arg_idx = first_def_arg + i;
            where_T     where = WHERE_INIT;
-           int         r;
            int         jump_instr_idx = instr->ga_len;
            isn_T       *isn;
  
            // Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
!           if (generate_JUMP_IF_ARG_SET(&cctx, i - count - off) == FAIL)
                goto erret;
  
            // Make sure later arguments are not found.
            ufunc->uf_args_visible = arg_idx;
  
!           arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
!           r = compile_expr0(&arg, &cctx);
! 
            if (r == FAIL)
                goto erret;
  
--- 3031,3057 ----
        SOURCING_LNUM = 0;  // line number unknown
        for (i = 0; i < count; ++i)
        {
+           char_u *arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
+           if (STRCMP(arg, "v:none") == 0)
+               // "arg = v:none" means the argument is optional without
+               // setting a value when the argument is missing.
+               continue;
+ 
            type_T      *val_type;
            int         arg_idx = first_def_arg + i;
            where_T     where = WHERE_INIT;
            int         jump_instr_idx = instr->ga_len;
            isn_T       *isn;
  
            // Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
!           if (generate_JUMP_IF_ARG(&cctx, ISN_JUMP_IF_ARG_SET,
!                                                     i - count - off) == FAIL)
                goto erret;
  
            // Make sure later arguments are not found.
            ufunc->uf_args_visible = arg_idx;
  
!           int r = compile_expr0(&arg, &cctx);
            if (r == FAIL)
                goto erret;
  
*** ../vim-9.0.1052/src/vim9execute.c   2022-12-10 18:42:09.090378817 +0000
--- src/vim9execute.c   2022-12-13 18:36:25.062067849 +0000
***************
*** 2068,2074 ****
  }
  
  /*
!  * Store a value in a list, dict or blob variable.
   * Returns OK, FAIL or NOTDONE (uncatchable error).
   */
      static int
--- 2068,2074 ----
  }
  
  /*
!  * Store a value in a list, dict, blob or object variable.
   * Returns OK, FAIL or NOTDONE (uncatchable error).
   */
      static int
***************
*** 2177,2185 ****
        {
            long            lidx = (long)tv_idx->vval.v_number;
            blob_T          *blob = tv_dest->vval.v_blob;
!           varnumber_T nr;
!           int     error = FALSE;
!           int     len;
  
            if (blob == NULL)
            {
--- 2177,2185 ----
        {
            long            lidx = (long)tv_idx->vval.v_number;
            blob_T          *blob = tv_dest->vval.v_blob;
!           varnumber_T     nr;
!           int             error = FALSE;
!           int             len;
  
            if (blob == NULL)
            {
***************
*** 2209,2214 ****
--- 2209,2215 ----
            long            idx = (long)tv_idx->vval.v_number;
            object_T        *obj = tv_dest->vval.v_object;
            typval_T        *otv = (typval_T *)(obj + 1);
+           clear_tv(&otv[idx]);
            otv[idx] = *tv;
        }
        else
***************
*** 4293,4302 ****
            // Jump if an argument with a default value was already set and not
            // v:none.
            case ISN_JUMP_IF_ARG_SET:
                tv = STACK_TV_VAR(iptr->isn_arg.jumparg.jump_arg_off);
!               if (tv->v_type != VAR_UNKNOWN
!                       && !(tv->v_type == VAR_SPECIAL
!                                           && tv->vval.v_number == VVAL_NONE))
                    ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
                break;
  
--- 4294,4305 ----
            // Jump if an argument with a default value was already set and not
            // v:none.
            case ISN_JUMP_IF_ARG_SET:
+           case ISN_JUMP_IF_ARG_NOT_SET:
                tv = STACK_TV_VAR(iptr->isn_arg.jumparg.jump_arg_off);
!               int arg_set = tv->v_type != VAR_UNKNOWN
!                               && !(tv->v_type == VAR_SPECIAL
!                                           && tv->vval.v_number == VVAL_NONE);
!               if (iptr->isn_type == ISN_JUMP_IF_ARG_SET ? arg_set : !arg_set)
                    ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
                break;
  
***************
*** 6632,6637 ****
--- 6635,6646 ----
                         iptr->isn_arg.jumparg.jump_arg_off + STACK_FRAME_SIZE,
                                                iptr->isn_arg.jump.jump_where);
                break;
+ 
+           case ISN_JUMP_IF_ARG_NOT_SET:
+               smsg("%s%4d JUMP_IF_ARG_NOT_SET arg[%d] -> %d", pfx, current,
+                        iptr->isn_arg.jumparg.jump_arg_off + STACK_FRAME_SIZE,
+                                               iptr->isn_arg.jump.jump_where);
+               break;
  
            case ISN_FOR:
                {
*** ../vim-9.0.1052/src/vim9instr.c     2022-12-10 18:42:09.094378801 +0000
--- src/vim9instr.c     2022-12-13 16:32:29.707108836 +0000
***************
*** 1408,1422 ****
  }
  
  /*
!  * Generate an ISN_JUMP_IF_ARG_SET instruction.
   */
      int
! generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr(cctx, ISN_JUMP_IF_ARG_SET)) == NULL)
        return FAIL;
      isn->isn_arg.jumparg.jump_arg_off = arg_off;
      // jump_where is set later
--- 1408,1422 ----
  }
  
  /*
!  * Generate an ISN_JUMP_IF_ARG_SET or ISN_JUMP_IF_ARG_NOT_SET instruction.
   */
      int
! generate_JUMP_IF_ARG(cctx_T *cctx, isntype_T isn_type, int arg_off)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr(cctx, isn_type)) == NULL)
        return FAIL;
      isn->isn_arg.jumparg.jump_arg_off = arg_off;
      // jump_where is set later
***************
*** 2479,2484 ****
--- 2479,2485 ----
        case ISN_GETITEM:
        case ISN_GET_OBJ_MEMBER:
        case ISN_JUMP:
+       case ISN_JUMP_IF_ARG_NOT_SET:
        case ISN_JUMP_IF_ARG_SET:
        case ISN_LISTAPPEND:
        case ISN_LISTINDEX:
*** ../vim-9.0.1052/src/proto/vim9instr.pro     2022-12-10 18:42:09.094378801 
+0000
--- src/proto/vim9instr.pro     2022-12-13 17:01:03.324121725 +0000
***************
*** 47,53 ****
  int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
  int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
  int generate_WHILE(cctx_T *cctx, int funcref_idx);
! int generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off);
  int generate_FOR(cctx_T *cctx, int loop_idx);
  int generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info);
  int generate_TRYCONT(cctx_T *cctx, int levels, int where);
--- 47,53 ----
  int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
  int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
  int generate_WHILE(cctx_T *cctx, int funcref_idx);
! int generate_JUMP_IF_ARG(cctx_T *cctx, isntype_T isn_type, int arg_off);
  int generate_FOR(cctx_T *cctx, int loop_idx);
  int generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info);
  int generate_TRYCONT(cctx_T *cctx, int levels, int where);
*** ../vim-9.0.1052/src/vim9.h  2022-12-10 18:42:09.094378801 +0000
--- src/vim9.h  2022-12-13 16:33:19.363129186 +0000
***************
*** 124,129 ****
--- 124,131 ----
      ISN_JUMP,     // jump if condition is matched isn_arg.jump
      ISN_JUMP_IF_ARG_SET, // jump if argument is already set, uses
                         // isn_arg.jumparg
+     ISN_JUMP_IF_ARG_NOT_SET, // jump if argument is not set, uses
+                        // isn_arg.jumparg
  
      // loop
      ISN_FOR,      // get next item from a list, uses isn_arg.forloop
***************
*** 260,266 ****
      int               jump_where;     // position to jump to
  } jump_T;
  
! // arguments to ISN_JUMP_IF_ARG_SET
  typedef struct {
      int               jump_arg_off;   // argument index, negative
      int               jump_where;     // position to jump to
--- 262,268 ----
      int               jump_where;     // position to jump to
  } jump_T;
  
! // arguments to ISN_JUMP_IF_ARG_SET and ISN_JUMP_IF_ARG_NOT_SET
  typedef struct {
      int               jump_arg_off;   // argument index, negative
      int               jump_where;     // position to jump to
*** ../vim-9.0.1052/src/testdir/test_vim9_class.vim     2022-12-10 
19:03:48.044388086 +0000
--- src/testdir/test_vim9_class.vim     2022-12-13 18:37:49.146067719 +0000
***************
*** 182,186 ****
--- 182,237 ----
    v9.CheckScriptSuccess(lines)
  enddef
  
+ def Test_class_default_new()
+   var lines =<< trim END
+       vim9script
+ 
+       class TextPosition
+         this.lnum: number = 1
+         this.col: number = 1
+       endclass
+ 
+       var pos = TextPosition.new()
+       assert_equal(1, pos.lnum)
+       assert_equal(1, pos.col)
+ 
+       pos = TextPosition.new(v:none, v:none)
+       assert_equal(1, pos.lnum)
+       assert_equal(1, pos.col)
+ 
+       pos = TextPosition.new(3, 22)
+       assert_equal(3, pos.lnum)
+       assert_equal(22, pos.col)
+ 
+       pos = TextPosition.new(v:none, 33)
+       assert_equal(1, pos.lnum)
+       assert_equal(33, pos.col)
+   END
+   v9.CheckScriptSuccess(lines)
+ 
+   lines =<< trim END
+       vim9script
+       class Person
+         this.name: string
+         this.age: number = 42
+         this.education: string = "unknown"
+ 
+         def new(this.name, this.age = v:none, this.education = v:none)
+         enddef
+       endclass
+ 
+       var piet = Person.new("Piet")
+       assert_equal("Piet", piet.name)
+       assert_equal(42, piet.age)
+       assert_equal("unknown", piet.education)
+ 
+       var chris = Person.new("Chris", 4, "none")
+       assert_equal("Chris", chris.name)
+       assert_equal(4, chris.age)
+       assert_equal("none", chris.education)
+   END
+   v9.CheckScriptSuccess(lines)
+ enddef
+ 
  
  " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-9.0.1052/src/version.c       2022-12-13 13:42:32.179427634 +0000
--- src/version.c       2022-12-13 18:21:37.554157231 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1053,
  /**/

-- 
GALAHAD: No. Look, I can tackle this lot single-handed!
GIRLS:   Yes, yes, let him Tackle us single-handed!
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20221213184356.014A71C0BAE%40moolenaar.net.

Raspunde prin e-mail lui