Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: Unclear on syntax for returning from a lisp function created in c#

  1. #1
    Active Member
    Join Date
    2008-02
    Location
    Toronto, On
    Posts
    59
    Login to Give a bone
    0

    Default Unclear on syntax for returning from a lisp function created in c#

    So I'm trying to understand the process for creating a Lisp function in c# .net.


    Code:
    public class LispException : System.Exception
            {
                public LispException(string msg) : base(msg) { }
            }
    
            public class TooFewArgsException : LispException
            {
                public TooFewArgsException() : base("too few arguments") { }
            }
    
            public class TooManyArgsException : LispException
            {
                public TooManyArgsException() : base("too many arguments") { }
            }
    
            public class ArgumentTypeException : LispException
            {
                public ArgumentTypeException(string s, TypedValue tv)
                    : base(string.Format("Bad argument type: {0} {1}", s, tv.TypeCode == (int)LispDataType.Nil ? "nil" : tv.Value)) { }
            }
    
    
    
    
    
            [LispFunction("DoubleValue")]
            public object DoubleValue(ResultBuffer argBuffer)
            {
                Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
                Object Res = new ResultBuffer();
    
                try
                {
                    if (argBuffer == null)
                    {
                        throw new TooFewArgsException();
                    }
                    else
                    {
                        TypedValue[] argArray = argBuffer.AsArray();
                        int ArrayLen = argArray.Length;
    
                        if (ArrayLen > 1)
                        {
                            throw new TooManyArgsException();
                        }
    
                        else
                        {
    
                            if (argArray[0].TypeCode == (short)LispDataType.Double)
                            {
                                Res = ((double)argArray[0].Value) * 2.0;
                            }
                            else if (argArray[0].TypeCode == (short)LispDataType.Int16)
                            {
                                Res = ((Int16)argArray[0].Value) * 2;
                            }
                            else if (argArray[0].TypeCode == (short)LispDataType.Int32)
                            {
                                Res = ((Int32)argArray[0].Value) * 2;
                            }
                            else
                            {
                                throw new ArgumentTypeException("numberp", argArray[0]);
                            }
                        }
                    }
    
                    return Res;
                }//end try
    
                
                catch (LispException ex)
                {
                    ed.WriteMessage("\n; error: {0}\n", ex.Message);
                    return null;
                }
    
                catch (Autodesk.AutoCAD.Runtime.Exception ex)
                {
                    ed.WriteMessage("\nAutoCAD error: {0}\n", ex.Message);
                    return null;
                }
    
                catch (System.Exception ex)
                {
                    ed.WriteMessage("\nSystem error: {0}\n", ex.Message);
                    return null;
                }
            }

    I can netload this without a problem, and it does what it's supposed to do...up to a point...

    Code:
    Command: (setq Num 12)
    12
    
    Command: (setq Num (DoubleValue Num))
    24
    
    Command: (setq Num (DoubleValue 12.34))
    24.68
    
    Command: (setq Num (abs))
    ; error: too few arguments
    
    Command: !Num
    24.68
    
    Command: (setq Num (DoubleValue))
    
    ; error: too few arguments
    nil
    
    Command: !Num
    nil
    Notice that the call to (abs) with no arguments resulted in an error, but (abs) didn't return a value to the setq, so Num kept it's previous value.
    How do I create a Lisp function in c# that will properly catch exceptions, but not return nil to the calling function, just like normal autolisp functions?

    Thanks!

  2. #2
    Administrator BlackBox's Avatar
    Join Date
    2009-11
    Posts
    5,714
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Couple of things....

    Quote Originally Posted by JaCAD View Post
    So I'm trying to understand the process for creating a Lisp function in c# .net.

    Code:
    public class LispException : System.Exception
            {
                public LispException(string msg) : base(msg) { }
            }
    
            public class TooFewArgsException : LispException
            {
                public TooFewArgsException() : base("too few arguments") { }
            }
    
            public class TooManyArgsException : LispException
            {
                public TooManyArgsException() : base("too many arguments") { }
            }
    
            public class ArgumentTypeException : LispException
            {
                public ArgumentTypeException(string s, TypedValue tv)
                    : base(string.Format("Bad argument type: {0} {1}", s, tv.TypeCode == (int)LispDataType.Nil ? "nil" : tv.Value)) { }
            }
    Firstly, when copying someone else's code, be sure to credit them, and include a link when possible. I can recognize Gile's LispException Classes anywhere, as he shared them with me when I was first learning to work with LispFunction Methods.


    Quote Originally Posted by JaCAD View Post
    I can netload this without a problem, and it does what it's supposed to do...up to a point...

    Code:
    Command: (setq Num 12)
    12
    
    Command: (setq Num (DoubleValue Num))
    24
    
    Command: (setq Num (DoubleValue 12.34))
    24.68
    
    Command: (setq Num (abs))
    ; error: too few arguments
    
    Command: !Num
    24.68
    
    Command: (setq Num (DoubleValue))
    
    ; error: too few arguments
    nil
    
    Command: !Num
    nil
    Notice that the call to (abs) with no arguments resulted in an error, but (abs) didn't return a value to the setq, so Num kept it's previous value.
    How do I create a Lisp function in c# that will properly catch exceptions, but not return nil to the calling function, just like normal autolisp functions?
    Simple, either return false, or a ResultBuffer with a Nil LispDataType... Just be sure to handle any Exception(s), as not every LispFunction Method will do simple Math calculations.
    "How we think determines what we do, and what we do determines what we get."

    Sincpac C3D ~ Autodesk Exchange Apps

    Computer Specs:
    Dell Precision 3660, Core i9-12900K 5.2GHz, 64GB DDR5 RAM, PCIe 4.0 M.2 SSD (RAID 0), 16GB NVIDIA RTX A4000

  3. #3
    Administrator BlackBox's Avatar
    Join Date
    2009-11
    Posts
    5,714
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Consider this adaptation:

    Code:
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.Runtime;
    
    using System;
    
    [assembly: CommandClass(typeof(AUGI.Sample.LispFunctions.Commands))]
    
    namespace AUGI.Sample.LispFunctions
    {
        public class Commands
        {
            [LispFunction("2X")]
            public object Double(ResultBuffer resbuf)
            {
                if (resbuf == null)
                    return false;
    
                TypedValue[] args = resbuf.AsArray();
    
                if (args.Length != 1)
                    return false;
    
                TypedValue arg = args[0];
                short type = arg.TypeCode;
    
                if (type == (short)LispDataType.Double)
                    return ((double)arg.Value) * 2.0;
    
                if (type == (short)LispDataType.Int16)
                    return ((Int16)arg.Value) * 2;
    
                if (type == (short)LispDataType.Int32)
                    return ((Int32)arg.Value) * 2;
    
                return false;
            }
        }
    }
    "How we think determines what we do, and what we do determines what we get."

    Sincpac C3D ~ Autodesk Exchange Apps

    Computer Specs:
    Dell Precision 3660, Core i9-12900K 5.2GHz, 64GB DDR5 RAM, PCIe 4.0 M.2 SSD (RAID 0), 16GB NVIDIA RTX A4000

  4. #4
    I could stop if I wanted to
    Join Date
    2007-08
    Posts
    201
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Hi,
    How do I create a Lisp function in c# that will properly catch exceptions, but not return nil to the calling function, just like normal autolisp functions?
    It returns nil because your error handlers ends with: "return null;".
    To avoid this, you can re-throw the exception after having displayed the error message:
    Code:
    catch (LispException ex)
                {
                    MgdAcApplication.ShowAlertDialog(ex.Message);
                    throw;
                }
    
                catch (Autodesk.AutoCAD.Runtime.Exception ex)
                {
                    MgdAcApplication.ShowAlertDialog(ex.Message);
                    throw;
                }
    
                catch (System.Exception ex)
                {
                    MgdAcApplication.ShowAlertDialog(ex.Message);
                    throw;
                }
    PS: BlackBox, your adaptation should always return nil in case an exception is raised (nil stands for false too).
    Last edited by 'gile'; 2013-04-09 at 11:18 AM.

  5. #5
    Administrator BlackBox's Avatar
    Join Date
    2009-11
    Posts
    5,714
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Quote Originally Posted by 'gile' View Post
    PS: BlackBox, your adaptation should always return nil in case an exception is raised (nil stands for false too).
    It (my code) does always return Nil (false) in place of an Exception... However, unless I've overlooked something, Exception handling is only necessary when you've not accounted for a possible Exception through code logic... As I am using logical tests for each step, this is not necessary, as there are no Exceptions thrown.
    "How we think determines what we do, and what we do determines what we get."

    Sincpac C3D ~ Autodesk Exchange Apps

    Computer Specs:
    Dell Precision 3660, Core i9-12900K 5.2GHz, 64GB DDR5 RAM, PCIe 4.0 M.2 SSD (RAID 0), 16GB NVIDIA RTX A4000

  6. #6
    I could stop if I wanted to
    Join Date
    2007-08
    Posts
    201
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Quote Originally Posted by BlackBox View Post
    It (my code) does always return Nil (false) in place of an Exception... However, unless I've overlooked something, Exception handling is only necessary when you've not accounted for a possible Exception through code logic... As I am using logical tests for each step, this is not necessary, as there are no Exceptions thrown.
    I do not think so. An invalid input (as an invalid number or type of argument) have to throw an exception instead of returning a valid LISP value: nil.
    Your code hides the exception and may cause an exception later in the calling function:

    Code:
    (setq a (2x))
    ;; ...
    (princ (itoa a))
    ; error: Bad argument type: fixnump: nil

  7. #7
    Administrator BlackBox's Avatar
    Join Date
    2009-11
    Posts
    5,714
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Quote Originally Posted by 'gile' View Post
    I do not think so. An invalid input (as an invalid number or type of argument) have to throw an exception instead of returning a valid LISP value: nil.
    Your code hides the exception and may cause an exception later in the calling function:

    Code:
    (setq a (2x))
    ;; ...
    (princ (itoa a))
    ; error: Bad argument type: fixnump: nil
    Gile,

    Respectfully, the error you received is from supplying Nil to the ITOA function, which confirms that my code does properly return Nil.

    Code:
    _$ (setq a nil)
    nil
    _$ (princ (itoa a))
    ; error: bad argument type: fixnump: nil
    _$ 
    _$ !a
    nil
    _$ (= nil a (2x))
    T
    _$
    Please identify which line(s) in my code above would return an Exception, and I will gladly correct it.
    "How we think determines what we do, and what we do determines what we get."

    Sincpac C3D ~ Autodesk Exchange Apps

    Computer Specs:
    Dell Precision 3660, Core i9-12900K 5.2GHz, 64GB DDR5 RAM, PCIe 4.0 M.2 SSD (RAID 0), 16GB NVIDIA RTX A4000

  8. #8
    AUGI Addict fixo's Avatar
    Join Date
    2005-05
    Location
    Pietari, Venäjä
    Posts
    1,269
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Here is my attempt
    Code:
            [LispFunction("2X")]
            public static ResultBuffer twice(ResultBuffer resbuf)
            {
                ResultBuffer rb = new ResultBuffer();
    
                if (resbuf == null) return null;
    
                try
                {
                    TypedValue[] args = resbuf.AsArray();
    
                    if (args.Length != 1)
                        rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Nil) });
    
                    TypedValue arg = args[0];
                    short type = arg.TypeCode;
    
                    if (type == (short)LispDataType.Double)
                        rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Double, (double)arg.Value * 2) });
                    if (type == (short)LispDataType.Int16)
                        rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Double, (Int16)arg.Value * 2) });
                    if (type == (short)LispDataType.Int32)
                        rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Double, (Int32)arg.Value * 2) });
                    else if ((type == (short)LispDataType.Text) | (type == (short)LispDataType.Nil) | (type == (short)LispDataType.None))
                        rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Text, "\nInvalid data type\n") });
    
                    return rb;
                }
                catch (Autodesk.AutoCAD.Runtime.Exception ex)
                {
                    rb = new ResultBuffer(new TypedValue[] { new TypedValue((int)LispDataType.Text, "\n" + ex.ErrorStatus.ToString()) });
                    return rb;
                }
            }

  9. #9
    I could stop if I wanted to
    Join Date
    2007-08
    Posts
    201
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Respectfully, the error you received is from supplying Nil to the ITOA function, which confirms that my code does properly return Nil.
    That's exactly what I wanted to show. The user expects the '2x' function to return a number. While coding, he makes a typo: (setq a (2x)) then, uses the 'a' variable elsewhere in the code. An exception should be thrown from this place but not from the place the error in the code is (where the variable was set with an incorrect type).

    Built-in functions throws an exception for invalid inputs, they do not return nil and keep on evaluating.

    Please identify which line(s) in my code above would return an Exception, and I will gladly correct it.
    Exactly at the same places of JaCAD's code (without the unusefull else statements).

    Here's how I'd write it:
    Code:
            [LispFunction("2X")]
            public object Double(ResultBuffer resbuf)
            {
                try
                {
                    if (resbuf == null)
                        throw new TooFewArgsException();
    
                    TypedValue[] args = resbuf.AsArray();
    
                    if (args.Length > 1)
                        throw new TooManyArgsException();
    
                    switch (args[0].TypeCode)
                    {
                        case (short)LispDataType.Double:
                            return (double)args[0].Value * 2.0;
                        case (short)LispDataType.Int16:
                        case (short)LispDataType.Int32:
                            return Convert.ToInt32(args[0].Value) * 2;
                        default:
                            throw new ArgumentTypeException("numberp", args[0]);
                    }
                }
                catch (LispException ex)
                {
                    Application.ShowAlertDialog(ex.Message);
                    throw;
                }
            }
    Last edited by 'gile'; 2013-04-09 at 03:46 PM. Reason: error handling added

  10. #10
    Administrator BlackBox's Avatar
    Join Date
    2009-11
    Posts
    5,714
    Login to Give a bone
    0

    Default Re: Unclear on syntax for returning from a lisp function created in c#

    Gile,

    You well know that I both respect and admire you, and the work that you've done for this community. I am struggling to understand (perhaps due to a lack of education / experience on my part), as your argument (to me) seems to be one of preference, and not requirement.

    I agree that OOTB LispFunctions such as (1+) will throw an error instead of returning Nil, and that it is usually best to mimic the built-in functionality... However, I stand by this being discretionary, and not a mandatory requirement.

    If throwing LispExceptions were mandatory, then they would also be hard-coded into the API as is the case with many using directives, etc., and they are not.

    Quote Originally Posted by 'gile' View Post
    That's exactly what I wanted to show. The user expects the '2x' function to return a number. While coding, he makes a typo: (setq a (2x)) then, uses the 'a' variable elsewhere in the code. An exception should be thrown from this place but not from the place the error in the code is (where the variable was set with an incorrect type).
    Built-in functions throws an exception for invalid inputs , they do not return nil.
    Poor coding practices on the part of the user is not justification... This again demonstrates that code logic mitigates Error/Exception handling. I never claimed to mimic built-in functionality, and was quite clear about what the code does.

    I would never supply an argument to a function, not even (car (entsel)) without first checking it as being non-Nil before processing a dependent variable.

    Code:
    (if (setq a (2x))
      ;;<-- do work
      (prompt "\n** You made a mistake ** ")
    )


    Quote Originally Posted by 'gile' View Post
    Exactly at the same places of JaCAD's code (without the unusefull else statements).
    Side stepping the question with an ambiguous response, and a dig at the OP, is not an answer.

    In good faith, I added a try / catch block, and attempted myriad invalid combinations of arguments, and not one Exception was raised... Instead the code consistently returned false (Nil) at the appropriate line given the ResultBuffer supplied as intended.

    Quote Originally Posted by 'gile' View Post
    Here's how I'd write it:
    Code:
            [LispFunction("2X")]
            public object Double(ResultBuffer resbuf)
            {
                if (resbuf == null)
                    return false;  //<-- (setq a (2x))
    
                TypedValue[] args = resbuf.AsArray();
    
                if (args.Length > 1)
                    throw new TooManyArgsException(); 
    
                switch (args[0].TypeCode)
                {
                    case (short)LispDataType.Double:
                        return (double)args[0].Value * 2.0;
                    case (short)LispDataType.Int16:
                    case (short)LispDataType.Int32:
                        return (int)args[0].Value * 2;
                    default:
                        throw new ArgumentTypeException("numberp", args[0]);
                }
            }
    Respectfully, your own code also returns false (Nil), in lieu of an Exception when no argument is supplied.
    "How we think determines what we do, and what we do determines what we get."

    Sincpac C3D ~ Autodesk Exchange Apps

    Computer Specs:
    Dell Precision 3660, Core i9-12900K 5.2GHz, 64GB DDR5 RAM, PCIe 4.0 M.2 SSD (RAID 0), 16GB NVIDIA RTX A4000

Page 1 of 2 12 LastLast

Similar Threads

  1. Function "order and resize array" not returning values
    By CADfunk MC in forum VBA/COM Interop
    Replies: 8
    Last Post: 2015-01-06, 02:06 PM
  2. Common Lisp Object System (CLOS) Syntax
    By peter in forum Bridging the Gap: LISP -> .NET -> LISP
    Replies: 14
    Last Post: 2014-02-17, 02:20 AM
  3. LISP routine returning bad function error
    By playerdraft in forum AutoLISP
    Replies: 2
    Last Post: 2011-06-15, 04:38 PM
  4. Returning a SYMBOL using VB.Net Lisp Function
    By bweir in forum Dot Net API
    Replies: 0
    Last Post: 2007-05-11, 03:56 PM
  5. Is it possible to fill in a gap in an object created with the push/pull function?
    By bkolodzaike in forum AutoCAD 3D (2007 and above)
    Replies: 4
    Last Post: 2007-03-13, 01:26 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •