[ANSWERED] Is it possible to create a user defined code collapse area in Visual Studio?

Hey all

This isn’t strictly just a Unity question but I realise many people use Visual Studio for Unity development and people here are decent human beings so I though I would ask. Hope it’s ok. I’m still shocked how rude people can be on stackoverflow.

So …

I am using Visual Studio and I am wondering if it is possible to create my own collapsible areas of code? I would like to be able to collapse a whole section of code that has several methods in it like the following example.

+  < --- ALIENS --- >

  public void Aliens_Get(){
  //Do something
  }

  public void Aliens_Set(){
  //Do something
  }

  public void Aliens_Spawn(){
  //Do something
  }

  public void Aliens_Explode(){
  //Do something
  }   < --- ALIENS -END --- >

Many thanks

Paul

1 Like

Use region tags

#region Aliens
//code here
#endregion //Aliens

4 Likes

edit: bah pipped :stuck_out_tongue:

Regions, as mentioned above. However, remember that they in general are considered an Anti-Pattern, and should be avoided. Read a fairly comprehensive answer as to why here: c# - Are #regions an antipattern or code smell? - Software Engineering Stack Exchange (check the accepted answer)

While I rarely use them myself, I completely disagree that they’re an anti-pattern (as do a number of people in the comments). Regions are a tool like any other, and like any other tool can be used well or poorly.

3 Likes

Now that I know the pattern-Nazis hate them, I love regions even more.

7 Likes

I just logged in to like your post, seriously :smile:
btw, in wikipedia you can read that following patters is anti-pattern…

3 Likes

Agreed, I find regions very useful as well.

Especially in unity where breaking out into several classes isn’t always the best scenario for some tasks.

For example, an animation controller I might write could have several nested classes to handle states of the animation controller. Now I COULD break them out into their own code files, but why? They’re VERY specific to this one class, and breaking them out clutters up the folder where the animation controllers exist, which makes the designers job very annoying seeing 7 code files, for which only 1 is used, for a type of entities animations. A lot of my design is wrestling with designers in this case. They don’t understand why this “simple thing that just animates the player” requires 10 different classes… or to them, 10 different oddly named files like ‘PlayerAnimationController’, ‘PlayerAnimIdleState’, ‘PlayerAnimMovementState’, ‘PlayerAnimDeathState’, etc, etc.

Here’s an example of what I mean:

using UnityEngine;
using System.Collections.Generic;

using com.spacepuppy;
using com.spacepuppy.Anim;
using com.spacepuppy.Collections;
using com.spacepuppy.Scenario;
using com.spacepuppy.Utils;


namespace com.mansion.Entities.Actors.Player
{
  
    public class PlayerAnimator : SPComponent, IEntityAwakeHandler
    {

        #region Anim Constants

        public const int ANIMLAYER_DEFAULT = 0;
        public const int ANIMLAYER_WALK = 5;
        public const int ANIMLAYER_ACTION = 10;
        public const int ANIMLAYER_DEATH = 100;

        #endregion


        #region Fields

        [SerializeField()]
        [DefaultFromSelf(UseEntity = true)]
        private SPAnimationController _controller;

        [SerializeField()]
        private DefaultMovementAnimationInfo _defaultMovementAnimations;

        [SerializeField()]
        private UndeadMovementAnimationInfo _undeadAnimations;

        [SerializeField()]
        private RangeWeaponAnimationInfo _rangeWeaponAnimations;

        [SerializeField()]
        private StruckAnimationInfo _struckAnimations;

        [Header("Event Triggers")]
        [SerializeField()]
        private Trigger _onFireWeapon;
        [SerializeField()]
        private Trigger _onReloadWeapon;

        [SerializeField()]
        private Trigger _onStruck;
        [SerializeField()]
        private Trigger _onDeath;
        [SerializeField()]
        private Trigger _onRebirth;

        [SerializeField()]
        private Trigger _onUndeadAttack;


        [System.NonSerialized()]
        private IEntity _entity;

        #endregion

        #region CONSTRUCTOR

        protected override void Awake()
        {
            base.Awake();

            var entity = SPEntity.Pool.GetFromSource<IEntity>(this);
            if (entity != null && entity.IsAwake) this.OnAwake(entity);
        }

        void IEntityAwakeHandler.OnEntityAwake(SPEntity entity)
        {
            this.OnAwake(entity as IEntity);
        }

        private void OnAwake(IEntity entity)
        {
            _entity = entity;
            this.InitAnims();
        }

        #endregion

        #region Properties

        public IEntity Entity
        {
            get { return _entity; }
        }

        public SPAnimationController Controller
        {
            get { return _controller; }
        }

        public DefaultMovementAnimationInfo DefaultMovementAnimations
        {
            get { return _defaultMovementAnimations; }
        }

        public UndeadMovementAnimationInfo UndeadAnimations
        {
            get { return _undeadAnimations; }
        }

        public RangeWeaponAnimationInfo RangeWeaponAnimations
        {
            get { return _rangeWeaponAnimations; }
        }

        public StruckAnimationInfo StruckAnimations
        {
            get { return _struckAnimations; }
        }

        #endregion

        #region Methods

        private void InitAnims()
        {
            _defaultMovementAnimations.Init(this);
            _undeadAnimations.Init(this);
            _rangeWeaponAnimations.Init(this);
            _struckAnimations.Init(this);
        }

        #endregion

        #region Special Types

        [System.Serializable()]
        public class DefaultMovementAnimationInfo
        {

            public const string ANIM_MOVE_IDLE = "Idle";
            public const string ANIM_MOVE_IDLEACTION = "IdleAction";
            public const string ANIM_MOVE_WALK = "Walk";
            public const string ANIM_MOVE_STRAFE_F = "StrafeForward";
            public const string ANIM_MOVE_STRAFE_B = "StrafeBackward";
            public const string ANIM_MOVE_STRAFE_L = "StrafeLeft";
            public const string ANIM_MOVE_STRAFE_R = "StrafeRight";
            public const string ANIM_MOVE_IDLE_CRIT = "Idle_Crit";
            public const string ANIM_MOVE_IDLEACTION_CRIT = "IdleAction_Crit";
            public const string ANIM_MOVE_WALK_CRIT = "Walk_Crit";

            public enum DefaultMovementState
            {
                IdleAction = -1,
                Idle = 0,
                Walk = 1
            }

            #region Fields

            [SerializeField()]
            private float _moveAnimSpeedRatio = 1;
            [SerializeField()]
            private float _critMoveAnimSpeedRatio = 1;

            [SerializeField()]
            [SPAnimClipCollection.Config(DefaultLayer = PlayerAnimator.ANIMLAYER_DEFAULT)]
            [SPAnimClipCollection.StaticCollection(ANIM_MOVE_IDLE,
                                                   ANIM_MOVE_IDLEACTION,
                                                   ANIM_MOVE_WALK,
                                                   ANIM_MOVE_STRAFE_F,
                                                   ANIM_MOVE_STRAFE_B,
                                                   ANIM_MOVE_STRAFE_L,
                                                   ANIM_MOVE_STRAFE_R,
                                                   ANIM_MOVE_IDLE_CRIT,
                                                   ANIM_MOVE_IDLEACTION_CRIT,
                                                   ANIM_MOVE_WALK_CRIT)]
            private SPAnimClipCollection _animations;

            [System.NonSerialized()]
            private PlayerAnimator _owner;

            [System.NonSerialized()]
            private DefaultMovementState _state;
            [System.NonSerialized()]
            private SPAnimClip _currentWalk;

            #endregion

            #region CONSTRUCTOR

            #endregion

            #region Properties

            public DefaultMovementState State { get { return _state; } }

            #endregion

            #region Methods

            internal void Init(PlayerAnimator owner)
            {
                _owner = owner;
                _animations.Init(_owner.Controller, "*move");
                this.PlayIdle();
            }

            public SPAnim Play(string id, QueueMode queuMode = QueueMode.PlayNow, PlayMode playMode = PlayMode.StopSameLayer)
            {
                return _animations.Play(id, queuMode, playMode);
            }

            public void PlayIdle()
            {
                if (_currentWalk != null)
                {
                    _currentWalk.Stop();
                    _currentWalk = null;
                }

                SPAnimClip clip;
                if (_owner._entity.HealthMeter.Status == HealthMeter.StatusType.Critical)
                    clip = _animations[ANIM_MOVE_IDLE_CRIT];
                else
                    clip = _animations[ANIM_MOVE_IDLE];
                if (clip == null) return;

                clip.Layer = ANIMLAYER_DEFAULT;
                clip.CrossFadeDirectly(Constants.DEFAULT_CROSSFADE_DUR);
                _state = DefaultMovementState.Idle;
            }

            public void PlayIdleAction()
            {
                SPAnimClip clip;
                if (_owner._entity.HealthMeter.Status == HealthMeter.StatusType.Critical)
                    clip = _animations[ANIM_MOVE_IDLEACTION_CRIT];
                else
                    clip = _animations[ANIM_MOVE_IDLEACTION];
                if (clip == null) return;

                _state = DefaultMovementState.IdleAction;
                clip.WrapMode = WrapMode.Once;
                clip.Layer = ANIMLAYER_DEFAULT + 1;
                clip.CrossFade(Constants.DEFAULT_CROSSFADE_DUR).Schedule((a) =>
                {
                    if (_state == DefaultMovementState.IdleAction)
                    {
                        _state = DefaultMovementState.Idle;
                        this.PlayIdle();
                    }
                });
            }

            public void PlayWalk(float spd = 1f)
            {
                SPAnimClip clip;
                float ratio;
                if (_owner._entity.HealthMeter.Status == HealthMeter.StatusType.Critical)
                {
                    clip = _animations[ANIM_MOVE_WALK_CRIT];
                    ratio = _critMoveAnimSpeedRatio;
                }
                else
                {
                    clip = _animations[ANIM_MOVE_WALK];
                    ratio = _moveAnimSpeedRatio;
                }
                if (clip == null) return;

                clip.WrapMode = WrapMode.Loop;
                clip.Speed = spd * ratio;
                clip.Layer = ANIMLAYER_WALK;
                clip.CrossFadeDirectly(Constants.DEFAULT_CROSSFADE_DUR);
                _currentWalk = clip;
                _state = DefaultMovementState.Walk;
            }

            public void PlayStrafe(float offAngle, float spd = 1f)
            {
                SPAnimClip clip;
                if (Mathf.Abs(offAngle) >= 135f)
                    clip = _animations[ANIM_MOVE_STRAFE_B];
                else if (offAngle < -45f)
                    clip = _animations[ANIM_MOVE_STRAFE_L];
                else if (offAngle > 45f)
                    clip = _animations[ANIM_MOVE_STRAFE_R];
                else
                    clip = _animations[ANIM_MOVE_STRAFE_F];

                if (clip == null) return;

                clip.WrapMode = WrapMode.Loop;
                clip.Speed = spd * _moveAnimSpeedRatio;
                clip.Layer = ANIMLAYER_WALK;
                clip.CrossFadeDirectly(Constants.DEFAULT_CROSSFADE_DUR);
                _currentWalk = clip;
                _state = DefaultMovementState.Walk;
            }
          
            #endregion

        }

        [System.Serializable()]
        public class UndeadMovementAnimationInfo
        {

            public const string ANIM_UNDEAD_IDLE = "Idle";
            public const string ANIM_UNDEAD_IDLEACTION = "IdleAction";
            public const string ANIM_UNDEAD_WALK = "Walk";
            public const string ANIM_UNDEAD_MELEE = "Melee";

            public enum DefaultMovementState
            {
                IdleAction = -1,
                Idle = 0,
                Walk = 1
            }

            #region Fields

            [SerializeField()]
            private float _moveAnimSpeedRatio = 1;

            [SerializeField()]
            [SPAnimClipCollection.Config(DefaultLayer = PlayerAnimator.ANIMLAYER_DEFAULT)]
            [SPAnimClipCollection.StaticCollection(ANIM_UNDEAD_IDLE,
                                                   ANIM_UNDEAD_IDLEACTION,
                                                   ANIM_UNDEAD_WALK,
                                                   ANIM_UNDEAD_MELEE)]
            private SPAnimClipCollection _animations;

            [System.NonSerialized()]
            private PlayerAnimator _owner;

            [System.NonSerialized()]
            private DefaultMovementState _state;
            [System.NonSerialized()]
            private SPAnimClip _currentWalk;

            #endregion

            #region CONSTRUCTOR

            #endregion

            #region Properties

            public DefaultMovementState State { get { return _state; } }

            #endregion

            #region Methods

            internal void Init(PlayerAnimator owner)
            {
                _owner = owner;
                _animations.Init(_owner.Controller, "*undead");
                this.PlayIdle();
            }

            public SPAnim Play(string id, QueueMode queuMode = QueueMode.PlayNow, PlayMode playMode = PlayMode.StopSameLayer)
            {
                return _animations.Play(id, queuMode, playMode);
            }

            public void PlayIdle()
            {
                if (_currentWalk != null)
                {
                    _currentWalk.Stop();
                    _currentWalk = null;
                }


                var clip = _animations[ANIM_UNDEAD_IDLE];
                if (clip == null) return;

                clip.Layer = ANIMLAYER_DEFAULT;
                clip.CrossFadeDirectly(Constants.DEFAULT_CROSSFADE_DUR);
                _state = DefaultMovementState.Idle;
            }

            public void PlayIdleAction()
            {
                var clip = _animations[ANIM_UNDEAD_IDLEACTION];
                if (clip == null) return;

                _state = DefaultMovementState.IdleAction;
                clip.WrapMode = WrapMode.Once;
                clip.Layer = ANIMLAYER_DEFAULT + 1;
                clip.CrossFade(Constants.DEFAULT_CROSSFADE_DUR).Schedule((a) =>
                {
                    if (_state == DefaultMovementState.IdleAction)
                    {
                        _state = DefaultMovementState.Idle;
                        this.PlayIdle();
                    }
                });
            }

            public void PlayWalk(float spd = 1f)
            {
                var clip = _animations[ANIM_UNDEAD_WALK];
                if (clip == null) return;

                clip.WrapMode = WrapMode.Loop;
                clip.Speed = spd * _moveAnimSpeedRatio;
                clip.Layer = ANIMLAYER_WALK;
                clip.CrossFadeDirectly(Constants.DEFAULT_CROSSFADE_DUR);
                _currentWalk = clip;
                _state = DefaultMovementState.Walk;
            }

            public IRadicalWaitHandle PlayMelee()
            {
                var clip = _animations[ANIM_UNDEAD_MELEE];
                if (clip == null) return RadicalWaitHandle.Null;

                _owner._onUndeadAttack.ActivateTrigger();

                clip.WrapMode = WrapMode.Once;
                clip.Layer = ANIMLAYER_ACTION;
                var anim = clip.CrossFade(Constants.DEFAULT_CROSSFADE_DUR, QueueMode.PlayNow);
                return anim;
            }

            #endregion

        }

        [System.Serializable()]
        public class RangeWeaponAnimationInfo
        {

            public const string ANIM_RANGE_DRAW = "Draw";
            public const string ANIM_RANGE_AIM = "Aim";
            public const string ANIM_RANGE_HOLSTER = "Holster";
            public const string ANIM_RANGE_FIRE = "Fire";
            public const string ANIM_RANGE_RELOAD = "Reload";

            public enum RangeWeaponState
            {
                Holstering = -1,
                None = 0,
                Drawing = 1,
                Aim = 2,
                Firing = 3,
                Reload = 4
            }

            #region Fields
          
            [SerializeField()]
            [SPAnimClipCollection.Config(DefaultLayer = PlayerAnimator.ANIMLAYER_ACTION)]
            [SPAnimClipCollection.StaticCollection(ANIM_RANGE_DRAW,
                                                    ANIM_RANGE_AIM,
                                                    ANIM_RANGE_HOLSTER,
                                                    ANIM_RANGE_FIRE,
                                                    ANIM_RANGE_RELOAD)]
            private SPAnimClipCollection _animations;
          
            [System.NonSerialized()]
            private PlayerAnimator _owner;

            [System.NonSerialized()]
            private RangeWeaponState _state;

            [System.NonSerialized()]
            private SPAnim _drawAnim;

            #endregion

            #region CONSTRUCTOR

            #endregion

            #region Properties

            public RangeWeaponState State
            {
                get { return _state; }
            }

            #endregion

            #region Methods

            internal void Init(PlayerAnimator owner)
            {
                _owner = owner;
                _animations.Init(_owner.Controller, "*range");
            }

            public SPAnim Play(string id, QueueMode queuMode = QueueMode.PlayNow, PlayMode playMode = PlayMode.StopSameLayer)
            {
                return _animations.Play(id, queuMode, playMode);
            }

            public bool DrawWeapon()
            {
                switch (_state)
                {
                    case RangeWeaponState.Holstering:
                    case RangeWeaponState.None:
                        {
                            var clip1 = _animations[ANIM_RANGE_DRAW];
                            var clip2 = _animations[ANIM_RANGE_AIM];

                            if (clip1 == null || clip2 == null) return false;

                            _state = RangeWeaponState.Drawing;
                            clip1.WrapMode = WrapMode.Clamp;
                            clip1.Layer = ANIMLAYER_ACTION;
                            _drawAnim = clip1.Play(QueueMode.PlayNow);
                            _drawAnim.Schedule((a) =>
                            {
                                _drawAnim = null;
                                _state = RangeWeaponState.Aim;
                            });

                            clip2.WrapMode = WrapMode.Loop;
                            clip2.Layer = ANIMLAYER_ACTION;
                            clip2.Play(QueueMode.CompleteOthers);

                            return true;
                        }
                    case RangeWeaponState.Drawing:
                    case RangeWeaponState.Aim:
                    case RangeWeaponState.Firing:
                    case RangeWeaponState.Reload:
                    default:
                        return false;
                }
            }

            public bool HolsterWeapon()
            {
                switch(_state)
                {
                    case RangeWeaponState.Holstering:
                    case RangeWeaponState.None:
                        return false;
                    case RangeWeaponState.Drawing:
                        {
                            var clip = _animations[ANIM_RANGE_DRAW];

                            _state = RangeWeaponState.Holstering;
                            clip.WrapMode = WrapMode.Clamp;
                            clip.Layer = ANIMLAYER_ACTION;
                            clip.Time = _drawAnim.Time;
                            var anim = clip.Play(QueueMode.PlayNow);
                            anim.Speed = -1f;
                            anim.Schedule((a) =>
                            {
                                _state = RangeWeaponState.None;
                            });
                            _drawAnim = null;

                            return true;
                        }
                    case RangeWeaponState.Aim:
                        {
                            var clip = _animations[ANIM_RANGE_HOLSTER];
                            if (clip == null) return false;

                            _state = RangeWeaponState.Holstering;
                            clip.WrapMode = WrapMode.Once;
                            clip.Layer = ANIMLAYER_ACTION;
                            clip.CrossFade(Constants.DEFAULT_CROSSFADE_DUR, QueueMode.PlayNow).Schedule((a) =>
                            {
                                _state = RangeWeaponState.None;
                            });

                            return true;
                        }
                    case RangeWeaponState.Firing:
                    case RangeWeaponState.Reload:
                    default:
                        return false;
                }
            }

            public bool FireWeapon()
            {
                switch (_state)
                {
                    case RangeWeaponState.Holstering:
                    case RangeWeaponState.None:
                    case RangeWeaponState.Drawing:
                        return false;
                    case RangeWeaponState.Aim:
                        {
                            var clip = _animations[ANIM_RANGE_FIRE];
                            if (clip == null) return false;
                          
                            _state = RangeWeaponState.Firing;
                            clip.WrapMode = WrapMode.Once;
                            clip.Layer = ANIMLAYER_ACTION + 1;
                            clip.Play(QueueMode.CompleteOthers).Schedule((a) =>
                            {
                                _state = RangeWeaponState.Aim;
                            });

                            _owner._onFireWeapon.ActivateTrigger();

                            return true;
                        }
                    case RangeWeaponState.Firing:
                    case RangeWeaponState.Reload:
                    default:
                        return false;
                }
            }

            public bool ReloadWeapon()
            {
                switch (_state)
                {
                    case RangeWeaponState.Holstering:
                    case RangeWeaponState.None:
                    case RangeWeaponState.Drawing:
                        return false;
                    case RangeWeaponState.Aim:
                        {
                            var clip = _animations[ANIM_RANGE_RELOAD];
                            if (clip == null) return false;

                            _state = RangeWeaponState.Reload;
                            clip.WrapMode = WrapMode.Once;
                            clip.Layer = ANIMLAYER_ACTION + 1;
                            clip.Play(QueueMode.CompleteOthers).Schedule((a) =>
                            {
                                _state = RangeWeaponState.Aim;
                            });

                            _owner._onReloadWeapon.ActivateTrigger();

                            return true;
                        }
                    case RangeWeaponState.Firing:
                    case RangeWeaponState.Reload:
                    default:
                        return false;
                }
            }

            #endregion

        }
      

        [System.Serializable()]
        public class StruckAnimationInfo
        {

            public const string ANIM_STRUCK_DEATH = "Death";
            public const string ANIM_STRUCK_REBIRTH = "Rebirth";

            #region Fields

            [SerializeField()]
            [SPAnimClipCollection.Config(DefaultLayer = PlayerAnimator.ANIMLAYER_ACTION)]
            private SPAnimClipCollection _struckAnimations;

            [SerializeField()]
            [SPAnimClipCollection.Config(DefaultLayer = PlayerAnimator.ANIMLAYER_DEATH)]
            [SPAnimClipCollection.StaticCollection(ANIM_STRUCK_DEATH,
                                                    ANIM_STRUCK_REBIRTH)]
            private SPAnimClipCollection _deathAnimations;

            [System.NonSerialized()]
            private PlayerAnimator _owner;

            #endregion

            #region Methods

            internal void Init(PlayerAnimator owner)
            {
                _owner = owner;
                _struckAnimations.Init(_owner.Controller, "*struck");
                _deathAnimations.Init(_owner.Controller, "*death");
            }

            public SPAnim PlayStruck()
            {
                var clip = _struckAnimations.PickRandom();
                if (clip == null) return null;

                _owner._onStruck.ActivateTrigger();

                return clip.Play();
            }

            public SPAnim PlayDeath()
            {
                var clip = _deathAnimations[ANIM_STRUCK_DEATH];
                if (clip == null) return null;

                _owner._onDeath.ActivateTrigger();

                clip.Layer = PlayerAnimator.ANIMLAYER_DEATH;
                clip.WrapMode = WrapMode.ClampForever;
                return clip.CrossFade(0.5f);
            }

            public SPAnim PlayRebirth()
            {
                var clip = _deathAnimations[ANIM_STRUCK_REBIRTH];
                if (clip == null) return null;

                _owner._onRebirth.ActivateTrigger();

                clip.Layer = PlayerAnimator.ANIMLAYER_DEATH;
                return clip.CrossFade(1f);
            }

            #endregion

        }

        #endregion

    }

}

Note my ‘special tpes’ region. I have no reason to break this thing out into their own classes. While at the same time, grouping them into a region does let me close them up and not have to pay attention to them while working with other code in the class.

Call me ADD, but I find all the extra code distracting while I happen to be working in one specific area. I like to get out of my sight for a moment. It’s not like I forget its there… I KNOW its there. My regions follow a standard (it’s my standard, but still a standard), I don’t shrink the Properties region and go “Ope, I don’t have any properties in this class!”.

Others are like the Fields. Sure, they follow naming conventions that make them distinct… I’m not going to confuse my fields with my constants with my properties. And they’re grouped appropriately. Which that stack-exchange or whatever says should be enough.

But… look at all those attributes? I need them! But they’re really distracting to look at. So yeah, I hide them away when I don’t need them.

And yeah, sure, I could rewrite this damn thing in so many different ways that gets rid of the regions. But why… why do that? It works! And it’s readable for most with any reasonable programming skill. I get saying a region inside a method is bad… your method might be too big (is that even allowed in C#?), but screw you that the mere use of them is bad. pffffff yep, and goto’s and singletons are evil, and oop design patterns set back programming 30 years, and so on and so forth.

These are the same sorts who think all code should be written in Haskell, in ONLY Debian Linux (or insert some other distribution), while typing upside down in pig latin. Why? Because that’s what they do, and you should do it too. Nothing’s wrong with these tools, but using them and only them, while excluding others just as viable, is stupid.

4 Likes

Agreed. When used correctly, I see nothing wrong with regions. While I understand a few things mentioned, I’m not going to avoid them either. For example, I have a class that handles all interactions with our backend service. Some methods are for saving and some are for loading. I tend to group these together based on what they may be doing. This is especially useful when passing to another developer at work and they may just want to see how a certain part is implemented.

Sure, there are ways to go straight to a method, but if they can find a region tag that says “Handles player data” they can just expand that and get access to all methods dealing with that.

Also, I don’t know about other people, but I use ctrl+f a LOT.

That link criticizes that a CONSTRUCTOR region is useless, since a lot of classes only have 1 constructor anyways. So now you have a region around 1 thing.

Sure…

But, that one thing isn’t named anything that jumps out as a constructor right away. Now yes, if you know the name of the class you’re in, and you read the method, you’ll know its shaped as a constructor. Totally agree…

But what about when I’m scrolling down at 100 rpm. I’ve worked in business application development for years… and, those libraries get MASSIVE. Especially since certain types of code reuse is actually shunned because it can cause one part of a program to break when some greenthumb comes in and mucks around in it trying to make something work elsewhere… business software isn’t designed to be beautiful, its designed to get a job done with as little amount of man hours as possible… because bottom line (note, I hate working in these settings). But even foregoing that, libraries can grow massive. Just look at the Unity library, or my own Spacepuppy Framework (of which I only share a tiny bit), these are huge. So yeah, I scroll through stuff fast. My brain isn’t going to pick those things up that quickly… my brain isn’t going to equivocate the fact a method is shaped ‘NameOfClass()’ as being the constructor unless you scroll by more moderately.

Furthermore, it makes it near impossible with ctrl+f. Now I need extra information! Where as with a region that I always title ‘CONSTRUCTOR’… yeah, I can ctrl+f the same simple statement no matter where I am. I don’t have to touch the mouse (heck, I might not even have mouse functionality, I might be in vim for all I know).

Sorry…

I just hate it when people take SIMPLE tools and demonize them as the most horrible things in coding.

I’ve been writing python the past few days, and the editor I’m using has lynting and whatnot built in. Mainly because I want intellisense in what is a loosely typed language that drives me nuts. But by default these freaking lynters/intellisense tools also have a code cop built in… telling me I used the wrong formatted name for this, or my line is too long for that. I’m constantly getting berated about stupid shit.

Yes, I get it, my 101 character long line is 1 character too long for what the lynter thinks is appropriate. It’s a string though, I can’t avoid its length, and I really don’t care to go through the bs of multilining it… ok, I’ll do it… oh great, now this line of code broke because the new white space implied to the compiler that we’re in a new scope… omg, what is going on, now there’s more warnings and errors…

and turn that shit off

Why did I have to do extra work for this (it’s always hidden too)… I just wanted that when I said ‘obj.’, a list of known fields appeared.

I hate you stupid code cop standards.

I hate you with a passion.

A passion that burns so strong I’ve ranted about it for this long in a thread on unity.

BURN!!!

4 Likes

I’m not sure at all, but I think maybe we touched on a sore subject. Maybe.

4 Likes

At work, the moment somebody utters the word “pattern” they go on my internal “suspicious until proven otherwise” list.

1 Like

Brilliant Guys, thank you.

This forum teaches me so much :slight_smile:

While this old man is learning coding again, anything that keeps me focused on my task in hand, while i’m thinking of n things at once, trying to hold onto to a new concept, syntax and think of my relative position, … is all good and this one thing is bloody amazing.

1 Like

Joking aside…

I use regions in many of the same ways @lordofduct listed (grouping properties, constructors, etc) but another place I find them very handy is grouping interface implementations on classes with multiple interfaces. I also comment my code very heavily, and sometimes I’ll wrap a particularly long comment in a region and collapse that.

4 Likes

Yep, interface implementations are a big one for me as well.

3 Likes

I’m not sure I could write a moderately complex script these days without using regions.

I get some of the SO points. Regions let you make a class more complex then you can without regions. But some tasks are simply inherently complex. Breaking them up into multiple classes doesn’t actually make the complexity go away. It just hides it differently.

And the other main argument, that it lets you hide code, is completely irrelevant. OOP is fundamentally predicated in having most of your code hidden from the developer at any given time. Regions are just another tool to facilitate this.

Wow. We broke @lordofduct . Which to me is the final nail in the coffin for this one.

If our normally calm and rational structure expert thinks it’s rubbish, it probably is rubbish.

2 Likes